你能用data.table
并行聚合吗?可以。
这么做值得吗?不值得。这是前面回答没有强调的关键点。
正如Matt Dowle在data.table和并行计算中所解释的那样,在并行运行操作时,需要先进行复制(“分块”),然后再进行分发。这会降低速度。在某些情况下,当你无法使用data.table
(例如运行多个线性回归时),将任务分配给核心进行处理才是值得的。但是对于聚合,至少涉及到data.table
时并不值得这样做。
简而言之(在证明其它情况之前),使用data.table
进行聚合,别再为了潜在的速度提升而烦恼使用doMC
。在聚合方面,data.table
已经比任何其他可用工具都要快得多,即使没有多核支持!
以下是一些基准测试,你可以自己运行对比data.table
内部使用by
进行聚合和使用foreach
和mclapply
的结果排列在前面。
library(data.table)
N <- 1e4
set.seed(1)
a = sample(1:N, N*2, replace = TRUE)
b = sample(c("3m","2m2d2m","3m2d1i3s2d","5m","4m","9m","1m"), N*2, replace = TRUE)
d = sample(c("3m","2m2d2m","3m2d1i3s2d","5m","4m","9m","1m"), N*2, replace = TRUE)
e = a
dt = data.table(a = a, b = b, d = d, e = e, key="a")
setkey(dt, "a")
round(rowMeans(replicate(3, system.time({
dt[,list(b = paste(b, collapse=""), d = paste(d, collapse=""), e = e[1], by=a)]
}))), 3)
round(rowMeans(replicate(3, system.time({
results <- lapply(unique(dt[["a"]]), function(x) {
dt[.(x), list(b = paste(b, collapse=""), d = paste(d, collapse=""), e = e[1])]
})
rbindlist(results)
}))), 3)
round(rowMeans(replicate(3, system.time({
results <- mclapply(unique(dt[["a"]]),
function(x) {
dt[.(x), list(b = paste(b, collapse=""), d = paste(d, collapse=""), e = e[[1]])]
}, mc.cores=4)
rbindlist(results)
}))), 3)
library(doMC)
mc = 4
registerDoMC(cores=mc)
getDoParWorkers()
round(rowMeans(replicate(3, system.time({
foreach(x=unique(dt[["a"]]), .combine="rbind", .inorder=FALSE) %dopar%
dt[.(x) ,list(b = paste(b, collapse=""), d = paste(d, collapse=""), e = e[[1]])]
}))), 3)
round(rowMeans(replicate(3, system.time({
results <-
foreach(x=unique(dt[["a"]])) %dopar%
dt[.(x) ,list(b = paste(b, collapse=""), d = paste(d, collapse=""), e = e[[1]])]
rbindlist(results)
}))), 3)
registerDoSEQ()
getDoParWorkers()
read.index
是行索引,那么将每一行分组成一个单独的行肯定会很慢。你将会调用数百万次paste
。你使用了Rprof
吗?你使用了verbose=TRUE
吗?而且你使用了“太慢”的词汇,却没有给出具体数字。事实上,我现在已经自己说服自己要点踩了。如果你改进问题,它可以被撤销。 - Matt Dowle