R:在没有for循环的情况下将“短格式”数据转换为“长格式”数据?

时间:2011-05-04 00:28:34

标签: r dataframe

假设我有一个像这样的R数据帧:

  Subject Session  Property.A Property.B Property.C
1     100       1 -1.22527548 -0.9193751 -1.7501693
2     100      10  2.30627980  1.8940830 -0.8443976
3     100       2  2.33243332 -0.5860868 -4.2074489
4     100       3  0.38130810 -0.7336206  4.8016230
5     100       4  1.44685875  0.5066249  2.0138624
6     100       5  0.08907721 -0.3715202  1.4983700

我听说过这种称为“短格式”或“宽格式”的数据框架。现在假设我想让它看起来像这样,我听说它叫做“长形式”:

  Subject Session  Property    Value
1     100       1         A   -1.2252754
2     100       1         B   -0.9193751
3     100       1         C   -1.7501693
4     100       2         A    2.3324333
5     100       2         B   -0.5860868
6     100       2         C   -4.2074489

也就是说,我想要将N列减少到只有两个“名称/值”列,数据帧中的任何其他列都会根据需要扩展重复值。

显然我可以用一堆for循环执行这个转换,但这看起来真的很难看,如果/当我添加更多的属性列时,维护是很痛苦的。

有没有办法在R中用几行代码执行此操作?我还没有发现一些神奇的功能组合?

3 个答案:

答案 0 :(得分:11)

使用包melt中的reshape2功能:

library(reshape2)
dat.m <- melt(dat, id.vars = c("Subject", "Session"))

如果需要清理变量列的列名和/或值:

#change "variable" to "Property"
names(dat.m)[3] <- "Property"
#Drop "Property." from the column values
dat.m$Property <- gsub("Property\\.", "", dat.m$Property)

答案 1 :(得分:4)

我喜欢使用plyr函数,但是来自base的reshape函数非常强大,如下面的解决方案所示。

# create a dummy data frame
dat = data.frame(
  subject = rep(100, 5),
  session = sample(5, 10, replace = T),
  property.a = rnorm(5),
  property.b = rnorm(5),
  property.c = rnorm(5)
)

# convert wide to long, varying columns are 3:5, separator is "."
dat.long = reshape(dat, direction = 'long', varying = 3:5, sep = ".")

答案 2 :(得分:2)

重塑这个包非常适合这个但是......一堆循环不是替代方案。

也许这个例子很有启发性......

longDF <- lapply( 3:4, function(x) cbind(wideDF[1:2], p = names(wideDF)[x], wideDF[x]) )
longDF <- rbind( longDF )

或者这个

longDF <- cbind( rep(wideDF[1], 3), rep(wideDF[2], 3), c(wideDF[3], wideDF[4], wideDF[5]) )