正确/最快地重塑数据表的方法

我在R中有一个数据表:


library(data.table)

set.seed(1234)

DT <- data.table(x=rep(c(1,2,3),each=4), y=c("A","B"), v=sample(1:100,12))

DT

      x y  v

 [1,] 1 A 12

 [2,] 1 B 62

 [3,] 1 A 60

 [4,] 1 B 61

 [5,] 2 A 83

 [6,] 2 B 97

 [7,] 2 A  1

 [8,] 2 B 22

 [9,] 3 A 99

[10,] 3 B 47

[11,] 3 A 63

[12,] 3 B 49

我可以通过data.table中的组轻松地对变量v求和:


out <- DT[,list(SUM=sum(v)),by=list(x,y)]

out

     x  y SUM

[1,] 1 A  72

[2,] 1 B 123

[3,] 2 A  84

[4,] 2 B 119

[5,] 3 A 162

[6,] 3 B  96

但是,我想将组(y)作为列而不是行。我可以使用reshape以下方法完成此操作:


out <- reshape(out,direction='wide',idvar='x', timevar='y')

out

     x SUM.A SUM.B

[1,] 1    72   123

[2,] 2    84   119

[3,] 3   162    96

有聚合之后重塑数据更有效的方法?是否有任何方法可以使用data.table操作将这些操作组合为一个步骤?


慕妹3242003
浏览 629回答 3
3回答

GCT1015

该data.table软件包实现了更快的melt/dcast功能(用C语言编写)。通过允许熔化和浇铸多列,它还具有其他功能。请在Github上使用data.tables查看新的高效重塑。从v1.9.0版本开始提供data.table的melt / dcast功能,其功能包括:reshape2铸造前无需装载包装。但是,如果您希望将其加载用于其他操作,请在加载之前加载它data.table。dcast也是S3的通用名称。没有了dcast.data.table()。只需使用dcast()。melt:能够融化“列表”类型的列。获得variable.factor和value.factor,默认情况下分别为和,以TRUE与FALSE兼容reshape2。这样可以直接控制variable和value列的输出类型(是否为因子)。melt.data.table的na.rm = TRUE参数经过内部优化,可在熔化过程中直接去除NA,因此效率更高。新增:melt可以接受列表,列表measure.vars中每个元素中指定的列将合并在一起。通过使用进一步简化了此过程patterns()。dcast:接受多个fun.aggregate和多个 value.var。rowid()直接在公式中使用函数来生成ID列,有时需要ID来唯一地标识行。旧基准:melt :1000万行和5列,从61.3秒减少到1.2秒。dcast :1百万行4列,从192秒减少到3.6秒。科隆提醒(2013年12月)演示幻灯片32:为什么不向提交dcast拉取请求reshape2?

隔江千里

现在可以在data.table中实现此功能(从版本1.8.11开始)。所以我想有一个data.table解决方案。应用于此问题:library(data.table)set.seed(1234)DT <- data.table(x=rep(c(1,2,3),each=1e6),                   y=c("A","B"),                   v=sample(1:100,12))out <- DT[,list(SUM=sum(v)),by=list(x,y)]# edit (mnel) to avoid setNames which creates a copy# when calling `names<-` inside the functionout[, as.list(setattr(SUM, 'names', y)), by=list(x)]})   x        A        B1: 1 26499966 281666772: 2 26499978 281666733: 3 26500056 28166650这与DWin的方法具有相同的结果:tapply(DT$v,list(DT$x, DT$y), FUN=sum)         A        B1 26499966 281666772 26499978 281666733 26500056 28166650而且,它很快:system.time({    out <- DT[,list(SUM=sum(v)),by=list(x,y)]   out[, as.list(setattr(SUM, 'names', y)), by=list(x)]})##  user  system elapsed ## 0.64    0.05    0.70 system.time(tapply(DT$v,list(DT$x, DT$y), FUN=sum))## user  system elapsed ## 7.23    0.16    7.39 更新为了使该解决方案也适用于非平衡数据集(即某些组合不存在),您必须首先在数据表中输入这些组合:library(data.table)set.seed(1234)DT <- data.table(x=c(rep(c(1,2,3),each=4),3,4), y=c("A","B"), v=sample(1:100,14))out <- DT[,list(SUM=sum(v)),by=list(x,y)]setkey(out, x, y)intDT <- expand.grid(unique(out[,x]), unique(out[,y]))setnames(intDT, c("x", "y"))out <- out[intDT]out[, as.list(setattr(SUM, 'names', y)), by=list(x)]摘要结合上面的评论,这是一线解决方案:DT[, sum(v), keyby = list(x,y)][CJ(unique(x), unique(y)), allow.cartesian = T][,   setNames(as.list(V1), paste(y)), by = x]也可以很容易地修改它,使其不仅具有总和,例如:DT[, list(sum(v), mean(v)), keyby = list(x,y)][CJ(unique(x), unique(y)), allow.cartesian = T][,   setNames(as.list(c(V1, V2)), c(paste0(y,".sum"), paste0(y,".mean"))), by = x]#   x A.sum B.sum   A.mean B.mean#1: 1    72   123 36.00000   61.5#2: 2    84   119 42.00000   59.5#3: 3   187    96 62.33333   48.0#4: 4    NA    81       NA   81.0
打开App,查看更多内容
随时随地看视频慕课网APP