r - data.table lapply .SD 随着列数的增加而大幅减慢

标签 r performance data.table

我有一个 20k x 60k 的聚合表,并且正在试验以高内存使用效率和速度效率来实现的方法。我注意到 data.table 的速度随着列数的增加而急剧下降。例如:

library(data.table)  
# a 200 x 1,000 table.
test_dt= data.table(sample= rep(1:100,2), value= matrix(sample(6e07, 2e05), nrow = 200 ))
system.time(test_dt[, lapply(.SD, mean), by= sample, .SDcols= colnames(test_dt)[-1]])
#   user  system elapsed 
#  0.470   0.009   0.117 

# a 200 x 10, 000 table
test_dt= data.table(sample= rep(1:100,2), value= matrix(sample(6e07, 2e06), nrow = 200 ))
system.time(test_dt[, lapply(.SD, mean), by= sample, .SDcols= colnames(test_dt)[-1]])
#   user  system elapsed 
# 15.055   0.603  15.334 

关于这种非线性(10 倍列减速 100 倍)随时间增加的任何解释?解决此问题的一种方法是将其融化为长 DT。但是,它会消耗许多倍的内存。有没有办法在内存使用和速度之间实现协调?谢谢。

最佳答案

我看到与 OP 类似的结果:

# a 200 x 10, 000 table
set.seed(1)
test_dt= data.table(sample= rep(1:100,2), value= matrix(sample(6e07, 2e06), nrow = 200 ))[, 
  (2:10001) := lapply(.SD, as.numeric), .SDcols=2:10001]
system.time(z <- test_dt[, lapply(.SD, mean), by= sample])
#    user  system elapsed 
#   12.27    0.00   12.26

(我正在转换为数字,因为很明显这些将被视为浮点数;并添加 set.seed 以便在必要时更容易比较结果。)

Any explanation about this non-linear (100 times slow-down over 10 times column) increase in time?



通常,data.tables 和 data.frames 被优化以支持将行/观察分组在一起,而不是在大量列上进行迭代。我猜你的方法正在运行到你的 RAM 限制并使用交换内存......尽管我对此知之甚少。

我认为如果你想充分受益于 data.table 包的速度,你可能需要符合它的自然存储格式。如下所示,它产生了显着的差异。

One way to solve this is to melt it into long DT. However, it eats many folds more memory. Is there a way to achieve a reconciliation between the memory usage and speed?



我认为最好的方法是获得更多 RAM 并以长格式保存数据。我看到熔化的 table 大小大约是原来的两倍,但那里的计算速度快了 100 倍以上。
test_mdt = melt(test_dt, id = "sample")[, variable := match(variable, unique(variable))]

system.time(mz <- test_mdt[, .(res = mean(value)), by=.(sample, variable)])
#    user  system elapsed 
#    0.11    0.00    0.11 

object.size(test_dt)  # 17.8 MB
object.size(test_mdt) # 32.0 MB

或者,如果每个样本的大小相同,请使用矩阵列表或数组:
test_dt[, g := rowid(sample)]
test_mats = lapply( split(test_dt[, !"sample"], by="g", keep.by=FALSE), as.matrix )
system.time(matz <- Reduce(`+`, test_mats)/length(test_mats))
#    user  system elapsed 
#       0       0       0 

object.size(test_mats) # 17.3 MB

关于r - data.table lapply .SD 随着列数的增加而大幅减慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44470273/

相关文章:

r - 将不同大小的行变成列

r - One-hot 编码文本字符串

C Linux 中 C 查找耗时

java - HashMap 通过 2 种不同的方法进行操作 - 多线程和并发

r - 合并非关键变量的所有 "occurrences"

R data.table 到行列表;更好的方法?

r - 多个矩阵的元素之和

r - 控制knitr中两个并排图的对齐

r - R 中的 as.yearqtr 从 12 月而不是 1 月开始

javascript - 编写自定义 .on()/.bind() JavaScript 的最高效方式