如何在 R 中 "melt" 按行而不是按列?

How to "melt" row wise instead of column wise in R?

我有一个数据框 A,我想按行而不是按列融化,看起来像 B(这也不包括其中包含 NA 的观察结果)。这可以用 "melt" 函数来完成吗?

A <- read.table(text="  Id1 Id2 Var1    Var2    Var3    
            1   1   1   2   NA  
            1   2   NA  3   4   
            1   3   5   6   7   ", header=T)


B <- read.table(text="  Id1 Id2 NewVar  
    1   1   1   
    1   1   2   
    1   2   3   
    1   2   4   
    1   3   5   
    1   3   6   
    1   3   7   ", header=T)

我找到了一个类似问题的 answer,但该功能似乎有点矫枉过正,超出了我目前的 R 技能。

我们可以 ordermelting

之后
library(data.table)
melt(setDT(A), id.var = c("Id1", "Id2"), na.rm = TRUE, value.name = "NewVar"
     )[order(Id1, Id2)][, variable := NULL][]
#   Id1 Id2 NewVar
#1:   1   1     1
#2:   1   1     2
#3:   1   2     3
#4:   1   2     4
#5:   1   3     5
#6:   1   3     6
#7:   1   3     7

或者我们可以通过复制 'A' 的行扩展 'Id' 列来处理 base R,并且 cbind 转置非 ID 列, 连接起来。

`row.names<-`(na.omit(data.frame(A[rep(1:nrow(A), each =3), 1:2], 
                    NewVar= c(t(A[-(1:2)])))), NULL)
#  Id1 Id2 NewVar
#1   1   1      1
#2   1   1      2
#3   1   2      3
#4   1   2      4
#5   1   3      5
#6   1   3      6
#7   1   3      7

来自tidyverse,melt -> summarize -> unnest

library(reshape2)
library(tidyr)
melt(A, id=c("Id1", "Id2")) %>% group_by(Id1, Id2) %>%
  summarise(value=list(value[!is.na(value)])) %>% unnest()
# Source: local data frame [7 x 3]
# Groups: Id1 [1]
# 
#     Id1   Id2 value
#   <int> <int> <int>
# 1     1     1     1
# 2     1     1     2
# 3     1     2     3
# 4     1     2     4
# 5     1     3     5
# 6     1     3     6
# 7     1     3     7

编辑

由于 melt 有一个 NA 删除参数(来源:@Frank),一行就可以了。注意:此行是 akrun 的 data.table 方法的 reshape2 版本:

melt(A, id=c("Id1", "Id2"), na.rm=TRUE)[-3]

您可以将 dplyrtidyr 包中的 gather 一起使用:

library(dplyr)
library(tidyr)
A %>% gather(Key,NewVar,Var1:Var3) %>% 
      filter(!is.na(NewVar)) %>% 
      arrange(Id1,Id2) %>% select(-Key)
##  Id1 Id2 NewVar
##1   1   1      1
##2   1   1      2
##3   1   2      3
##4   1   2      4
##5   1   3      5
##6   1   3      6
##7   1   3      7

这会将 Var1:Var3 列收集到 NewVar 列中的行中。 Key 列将包含收集的列的名称,我们在最终结果中不需要这些名称。收集后,filter 取出 NewVar 中的 NA 行。然后按 ID1 排序,然后按 ID2 排序并删除 Key 列。