为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

慕妹3242003 2019-11-06 10:44:15
我在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操作将这些操作组合为一个步骤?
查看完整描述

3 回答

?
GCT1015

TA贡献1827条经验 获得超4个赞

该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?


查看完整回答
反对 回复 2019-11-06
?
隔江千里

TA贡献1906条经验 获得超10个赞

现在可以在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 function

out[, as.list(setattr(SUM, 'names', y)), by=list(x)]

})

   x        A        B

1: 1 26499966 28166677

2: 2 26499978 28166673

3: 3 26500056 28166650

这与DWin的方法具有相同的结果:


tapply(DT$v,list(DT$x, DT$y), FUN=sum)

         A        B

1 26499966 28166677

2 26499978 28166673

3 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


查看完整回答
反对 回复 2019-11-06
  • 3 回答
  • 0 关注
  • 622 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信