这被称为将数据从"宽"格式转换成"长"格式。在基础R中,有一个工具叫做reshape
。
reshape(df, direction = "long", varying = names(df), sep = "_")
如果需要,您可以删除其他列。
为了好玩,这里介绍另一种方法,使用“reshape2”包(从原始数据开始):
library(reshape2)
dfL <- melt(as.matrix(df))
dfL <- cbind(dfL, colsplit(dfL$Var2, "_", c("Factor", "Individual")))
dcast(dfL, Individual + Var1 ~ Factor, value.var="value")
如果你喜欢尝试最新的技术,“data.table”版本1.8.11现在已经实现了“melt”和“dcast”。我还没有深入使用过它,但它也很简单。与迄今为止提供的所有解决方案一样,都需要一个“id”。
library(reshape2)
library(data.table)
packageVersion("data.table")
DT <- data.table(cbind(id = sequence(nrow(df)), df))
DTL <- melt(DT, id.vars="id")
DTL[, c("Fac", "Ind") := colsplit(variable, "_", c("Fac", "Ind"))]
dcast.data.table(DTL, Ind + id ~ Fac)
更新
另一个选项是使用我的 "splitstackshape" 包中的 merged.stack
。如果您还使用 as.data.table(df, keep.rownames = TRUE)
,它将可以很好地工作,这将创建相当于 "data.table" 方法中的 data.table(cbind(id = sequence(nrow(df)), df))
步骤的等效内容。
library(splitstackshape)
merged.stack(as.data.table(df, keep.rownames = TRUE),
var.stubs = c("A", "B"), sep = "_")
为了公平和完整起见,这里介绍一种使用 "tidyr" + "dplyr" 的方法。
library(tidyr)
library(dplyr)
df %>%
gather(var, value, A_1:B_3) %>%
separate(var, c("var", "time")) %>%
group_by(var, time) %>%
mutate(grp = sequence(n())) %>%
ungroup() %>%
spread(var, value)