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代码来线性扩展呢?
答案 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在评论中提到的,我对您的数据大小做了一些假设。)