3 回答
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?
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
- 3 回答
- 0 关注
- 679 浏览
添加回答
举报