或者更为一般,它是DT[,.SD[...],by=...]
与merge(aggregate(...))
。
不用多说,这是数据和示例:
set.seed(5141)
size = 1e6
df <- data.table(a = rnorm(size),
b = paste0(sample(letters, size, T),
sample(letters, size, T),
sample(letters, size, T)),
c = sample(1:(size/10), size, T),
d = sample(seq.Date(as.Date("2015-01-01"),
as.Date("2015-05-31"), by="day"), size, T))
system.time(df[,.SD[d == max(d)], by = c])
# user system elapsed
# 50.89 0.00 51.00
system.time(merge(aggregate(d ~ c, data = df, max), df))
# user system elapsed
# 18.24 0.20 18.45
通常对data.table
性能没有任何问题,我对这个特定的例子感到惊讶。我不得不通过仅采用某些事件类型的最新(可以同时)出现来对一个相当大的数据帧进行子集(聚合)。并保留这些特定事件的其余相关数据。但是,似乎.SD
在这个特定的应用程序中不能很好地扩展。
是否有更好的“数据表方式”来处理这类任务?
答案 0 :(得分:8)
我们可以使用.I
获取行索引并根据该行对其进行子集化。它应该更快。
system.time(df[df[,.I[d == max(d)], by = c]$V1])
# user system elapsed
# 5.00 0.09 5.30
@Heroka的解决方案
system.time(df[,is_max:=d==max(d), by = c][is_max==T,])
# user system elapsed
# 5.06 0.00 5.12
我机器上的aggregate
方法提供了
system.time(merge(aggregate(d ~ c, data = df, max), df))
# user system elapsed
# 48.62 1.00 50.76
使用.SD
选项
system.time(df[,.SD[d == max(d)], by = c])
# user system elapsed
# 151.13 0.40 156.57
使用data.table
加入
system.time(df[df[, list(d=max(d)) , c], on=c('c', 'd')])
# user system elapsed
# 0.58 0.01 0.60
如果我们查看merge/aggregate
和==
之间的比较,它们就是不同的功能。通常,与aggregate/merge
的相应联接相比,data.table
方法会更慢。但是,我们正在使用==
来比较每一行(需要一些时间)和.SD
进行子集化(与行{1}}进行比较时,对于行索引也相对效率相对较低)。 .I
也有.SD
的开销。