R:data.table与merge(aggregate())性能

sta*_*ace 6 r data.table

或者更为一般,它是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 
Run Code Online (Sandbox Code Playgroud)

通常对data.table性能没有任何问题,我对这个特殊的例子感到惊讶.我不得不通过仅采用某些事件类型的最新(可以同时)出现来对一个相当大的数据帧进行子集(聚合).并保留这些特定事件的其余相关数据.但是,似乎.SD在这个特定应用中不能很好地扩展.

是否有更好的"数据表方式"来处理这类任务?

akr*_*run 8

我们可以.I用来获取行索引并根据它来对行进行子集化.它应该更快.

system.time(df[df[,.I[d == max(d)], by = c]$V1])
#    user  system elapsed 
#   5.00    0.09    5.30 
Run Code Online (Sandbox Code Playgroud)

@Heroka的解决方案

system.time(df[,is_max:=d==max(d), by = c][is_max==T,])
#   user  system elapsed 
#  5.06    0.00    5.12 
Run Code Online (Sandbox Code Playgroud)

aggregate我机器上的方法给出了

system.time(merge(aggregate(d ~ c, data = df, max), df))
#   user  system elapsed 
#  48.62    1.00   50.76 
Run Code Online (Sandbox Code Playgroud)

.SD选项

system.time(df[,.SD[d == max(d)], by = c])
#   user  system elapsed 
# 151.13    0.40  156.57 
Run Code Online (Sandbox Code Playgroud)

使用data.table连接

system.time(df[df[, list(d=max(d)) , c], on=c('c', 'd')])
#   user  system elapsed 
#   0.58    0.01    0.60 
Run Code Online (Sandbox Code Playgroud)

如果我们看一下merge/aggregate和之间的比较==,它们就是不同的功能.通常,aggregate/merge与相应的连接相比,该方法会更慢data.table.但是,我们正在使用==它来比较每一行(需要一些时间)以及.SD子集化(与.I行索引相比,它的效率也相对较低).该.SD还的开销[.data.table.