由于您不提供示例数据,
这是一个简单的示例,可以帮助您入门。
library(data.table)
library(doParallel)
dt <- data.table(a = sample(1:3, 1e6, TRUE),
b = sample(letters[1:5], 1e6, TRUE),
x = rnorm(1e6))
workers <- makeCluster(detectCores())
registerDoParallel(workers)
ids <- dt[, .(list(.I)), by = .(a, b)]
dt[unlist(ids$V1), y := foreach(i = ids$V1, .combine = c, .export = "dt", .packages = "data.table") %dopar% {
setDT(dt)[i, as.numeric(scale(x))]
}]
stopCluster(workers); registerDoSEQ(); rm(workers)
# sanity check
dt[, identical(y, as.numeric(scale(x))), by = .(a, b)]
a b V1
1: 2 c TRUE
2: 1 a TRUE
3: 3 d TRUE
4: 1 d TRUE
5: 1 b TRUE
6: 3 c TRUE
7: 2 e TRUE
8: 3 e TRUE
9: 2 a TRUE
10: 2 b TRUE
11: 2 d TRUE
12: 1 c TRUE
13: 3 a TRUE
14: 3 b TRUE
15: 1 e TRUE
我们首先获取每个组的行索引并将它们保存在ids
(在一个列表中,以便它们可以直接传递给foreach)。
分配y 的行将未列出的索引传递给data.table 的i,以便将foreach 的结果分配给适当的行。
我们在foreach 代码中使用setDT,因为表是序列化给工作人员的,
所以内存中的地址改变了
(至少我是这么认为的,也许其他人可以确认)。
一定要用您的实际功能对其进行基准测试,
使用foreach 不能保证加速。
鉴于序列化,
数据的副本可能开销太大,
相对而言。