Изменение формы от широкой к длинной с несколькими рядами - PullRequest
0 голосов
/ 21 февраля 2019

Это часть моего фрейма данных:

name      value_1  value_2  value_3
 AK          x       X
 AK          y       Y
 AK          m       M         B
 HU          z       Z
 HU          a       A
 HU          f       F         C
 KO          b       B
 KO          c       C
 KO          d       D         B

Мне нужно:

num   AK    HU   KO
 1    x      z   b
 1    X      Z   B
 2    y      a   c
 2    Y      A   C
 3    m      f   d
 3    M      F   D
 3    B      C   B 

В словах;У меня есть ценности для человека AK, HU и KO (и многих других).Все оцениваются одинаково - следовательно, число строк для каждого уникального идентификатора одинаково, и количество значений также будет одинаковым.В этой части данных фреймы 1 и 2 имеют два значения, 3 имеет 3 значения для каждого человека.Это на самом деле задача принудительного выбора, и, следовательно, значения в value_1: 2 на самом деле только 1 и 0, но я заменил их на aZ, чтобы показать сортировку.

Я пробовал:

library(reshape2)
long <- melt(df, id.vars = c("name"))

, однако, это не помогает, так как все они добавляются друг под другом, в то время как мне нужно, чтобы они были преобразованы в длинные в соответствии с их идентификатором (имя), но различные имена-идентификаторы необходимо будет поместить в отдельные столбцы рядом друг с другом.

Спасибо за помощь.

Ответы [ 4 ]

0 голосов
/ 21 февраля 2019

В качестве альтернативы здесь представлено решение, в котором используются melt() и dcast() из пакета .rowid(name) используется для создания номеров строк для каждого name индивидуально.

Воспроизводит ожидаемый результат, включая столбец num.

library(data.table)
long <- melt(setDT(df)[, num := rowid(name)], id.vars = c("num", "name"))[value != ""]
dcast(long, num + rowid(name) ~ name, value.var = "value")[, name := NULL][]
   num AK HU KO
1:   1  x  z  b
2:   1  X  Z  B
3:   2  y  a  c
4:   2  Y  A  C
5:   3  m  f  d
6:   3  M  F  D
7:   3  B  C  B

Данные

library(data.table)
df <- fread("
name      value_1  value_2  value_3
 AK          x       X
 AK          y       Y
 AK          m       M         B
 HU          z       Z
 HU          a       A
 HU          f       F         C
 KO          b       B
 KO          c       C
 KO          d       D         B", fill = TRUE)
0 голосов
/ 21 февраля 2019

Используя входные данные, показанные в примечании ниже, запустите melt, показанный в вопросе, а затем преобразуйте value_1, value_2 и value_3 в 1, 2 и 3, а также добавьте столбец subseqразличать строки, которые в противном случае имеют одинаковый ключ.Избавьтесь от пустых value строк и преобразуйте их в широкую форму, используя dcast, удалив столбец subseq:

library(reshape2)

long <- melt(DF, id.var = "name") # from question
long2 <- transform(long, num = gsub("\\D", "", variable),
          subseq =  ave(1:nrow(m), name, variable, FUN = seq_along),
          variable = NULL)
long3 <- subset(long2, value != "")
wide <- dcast(subseq + num ~ name, data = long3, value.var = "value")[-1]

, получив:

> wide
  num AK HU KO
1   1  x  z  b
2   2  X  Z  B
3   1  y  a  c
4   2  Y  A  C
5   1  m  f  d
6   2  M  F  D
7   3  B  C  B

Проверка на ожидаемое:

identical(wide, expected)
## [1] TRUE

Примечание

Входные данные в воспроизводимой форме:

Lines <- "
name      value_1  value_2  value_3
 AK          x       X
 AK          y       Y
 AK          m       M         B
 HU          z       Z
 HU          a       A
 HU          f       F         C
 KO          b       B
 KO          c       C
 KO          d       D         B"
DF <- read.table(text = Lines, header = TRUE, as.is = TRUE, fill = TRUE, strip.white = TRUE)

Мы предположили, что num является фактором, а другие данные являются символами - мыне могу сказать, что было задумано, поскольку входные данные не приведены в воспроизводимой форме в вопросе.

expected <- structure(list(num = structure(c(1L, 2L, 1L, 2L, 1L, 2L, 3L), .Label = 
c("1", "2", "3"), class = "factor"), AK = c("x", 
"X", "y", "Y", "m", "M", "B"), HU = c("z", "Z", "a", "A", "f", 
"F", "C"), KO = c("b", "B", "c", "C", "d", "D", "B")), row.names = c(NA, 
-7L), class = "data.frame")

Обновление 2

В этом варианте используются данные 0/1 и целое число num:

set.seed(123)
# test data
DF2 <- data.frame(name = DF$name, 
           value_1 = rbinom(9, 1, .5), 
           value_2 = rbinom(9, 1, .5),
           value_3 = ifelse(DF[, 4] == "", NA, rbinom(9, 1, .5)))

long <- melt(DF2, id.var = "name")
long2 <- subset(long, !is.na(value))
long3 <- transform(long2, num = as.integer(gsub("\\D", "", variable)),
           subseq =  ave(1:nrow(long2), name, variable, FUN = seq_along),
           variable = NULL)
wide <- dcast(subseq + num ~ name, data = long3, value.var = "value")[-1]

подача:

> wide
  num AK HU KO
1   1  0  1  1
2   2  0  1  1
3   3  1  1  1
4   1  1  1  1
5   2  1  1  0
6   1  0  0  1
7   2  0  0  0
0 голосов
/ 21 февраля 2019

Это обеспечит желаемый результат:

 library(tidyverse)
df0=df%>%mutate(Value12=map2(value_1,value_2,c))%>%
  mutate(Value=map2(Value12,value_3,c))%>%
  select(name,Value)%>%
  unnest()%>%
  drop_na()%>%
  group_by(name)%>%
   mutate(i = row_number())%>%
  spread(name,Value)%>%
  select(-i)


df0$num=cumsum(c(toupper(df0$AK)==toupper(lag(df0$AK)),F)%>%na.omit())
> df0
# A tibble: 7 x 4
  AK    HU    KO      num
  <chr> <chr> <chr> <int>
1 x     z     b         1
2 X     Z     B         1
3 y     a     c         2
4 Y     A     C         2
5 m     f     d         3
6 M     F     D         3
7 B     C     B         3

Однако вам необходимо уточнить, какова логика заполнения столбца num.Я должен был предположить, что одна и та же буква (без учета регистра) для столбца АК будет иметь тот же номер.

0 голосов
/ 21 февраля 2019

Мне пришлось добавить несколько небольших дополнительных шагов, чтобы сделать это, поскольку вы хотели получить вывод в определенном порядке, но это должно быть сделано:

long<-melt(df, id.vars=c("name"), value.var=c("value_1","value_2","value_3"))
long$variable<-c("11","21","31","11","21","31","11","21","31",
                 "12","22","32","12","22","32","12","22","32",
                 "13","23","33","13","23","33","13","23","33")
short<-dcast(long, variable ~ name)
final<-short[short$AK!="",]
final$variable<-round(as.numeric(final$variable)/10,0)
colnames(final)[1]<-"num"

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...