data.table性能在计算列的滞后差异时不能线性扩展

时间:2016-06-19 13:07:43

标签: r performance data.table

data.table相当新。经过两年的抵抗,我终于放弃了我的数据大小。我试图根据滞后时间差(POSIXct)按组计算“等待”时间,如下所示:

dt <- data.table(id = c(rep('a', 5), rep('b', 5)),
                 time = (Sys.time() + rnorm(10, 100, 10)))
dt <- dt[order(id, time)]
dt[, wait := difftime(time, shift(time, fill = min(time), type = 'lag'),
                      unit = 'mins'),
   by = id]

这样可以正常工作,但是当我在1150万行上运行它有近100,000个组(id)时,它需要大约10s(用户时间和经过时间),其中相同的代码在4500万行上有近200,000个组( id),它需要300多秒的用户时间(并且经过的时间超过730秒)。我正在用代码周围的system.time命令测量运行时间。

有关为何如此完全非线性扩展性能的想法?而且,我怎么可能通过编写更好的data.table代码来线性扩展呢?

1 个答案:

答案 0 :(得分:6)

您可以按分组变量对数据进行排序,对整个表格执行difftime,然后修复每个组的第一行:

ng = 1e5
n = 5L
set.seed(1)
dt <- data.table(
    id = rep(1:ng, n),
    time = (Sys.time() + rnorm(n*ng, 100, 10)))
setorder(dt, id, time)

system.time(
    dt[, wait := difftime(
       time, 
       shift(time, fill = min(time), type = 'lag'),
       unit = 'mins'
), by = id][]
)
#    user  system elapsed 
#    8.48    0.00    8.50 

system.time({
    dt[, wt := difftime(time, shift(time, fill=time[1L]), units='mins')][]
    dt[dt[,.I[1L], by=id]$V1, wt := 0][]
})
#    user  system elapsed 
#    0.03    0.00    0.04 

比较结果......

dt[wait != wt, summary(as.numeric(abs(wait - wt)))]
#      Min.   1st Qu.    Median      Mean   3rd Qu.      Max. 
# 3.179e-06 4.140e-05 9.469e-05 9.898e-05 1.274e-04 2.514e-04 

dt[, which.min(time), by=id][, table(V1)]
# V1
#     1     2 
# 99958    42

结果的微小差异是由于setorder中的某些四舍五入,但并不是很多,如此处所示。如果你使用的是time,那么我猜你根本就不会看到这个。如果您确实需要时间与最短时间,则可以在setNumericRounding(0)之前使用setorder

(正如Arun在评论中提到的,我对您的数据大小做了一些假设。)