从多行重整为长

时间:2019-02-21 13:18:22

标签: r transpose

这是我数据框的一部分:

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(以及许多其他人)具有价值。所有的等级都相同-因此,每个唯一ID的行数是相同的,值的数量也将是相同的。 在数据帧的这一部分中,每个人的1和2具有两个值,3具有3个值。 它实际上是强制选择任务,因此value_1:2中的值实际上仅是1和0,但我已将它们替换为a-Z以显示排序。

我尝试过:

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

不能解决问题,因为所有内容都添加在彼此之间,而我需要根据其ID(名称)将它们重塑为长,但是随后需要将不同的名称ID放在其中彼此相邻的独立列。

感谢您的帮助。

4 个答案:

答案 0 :(得分:0)

我必须包括一些额外的小步骤来完成此操作,因为您希望按照特定的顺序进行输出,但这应该做到:

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"

希望这会有所帮助!

答案 1 :(得分:0)

使用以下注释中显示的输入,运行问题中显示的melt,然后将value_1value_2value_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

答案 2 :(得分:0)

这将提供所需的输出:

 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的逻辑。我必须为列AK假定相同的字母(不区分大小写)具有相同的数字。

答案 3 :(得分:0)

或者,这是一个使用包中的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)