[英]Fast alternative to split in R
我正在使用split()
对数据帧进行分区,以便使用parLapply()
并行调用每个分区上的函数。 数据框有 130 万行和 20 列。 我按两列拆分/分区,都是字符类型。 看起来有 ~47K 唯一 ID 和 ~12K 唯一代码,但并非每个 ID 和代码配对都匹配。 结果分区数约为 250K。 这是split()
行:
system.time(pop_part <- split(pop, list(pop$ID, pop$code)))
然后分区将被送入parLapply()
,如下所示:
cl <- makeCluster(detectCores())
system.time(par_pop <- parLapply(cl, pop_part, func))
stopCluster(cl)
我让split()
代码单独运行了将近一个小时,但它没有完成。 我可以单独按 ID 拆分,这需要大约 10 分钟。 此外,R studio 和工作线程消耗了大约 6GB 的 RAM。
我知道结果分区数的原因是我在 Pentaho 数据集成 (PDI) 中有等效的代码,它在 30 秒内运行(对于整个程序,而不仅仅是“拆分”代码)。 我不希望 R 能有那种表现,但最坏的情况可能会在 10 - 15 分钟内完成。
主要问题:有没有更好的分割替代方案? 我也试过ddply()
和.parallel = TRUE
,但它也运行了一个多小时并且从未完成。
将索引拆分为pop
idx <- split(seq_len(nrow(pop)), list(pop$ID, pop$code))
拆分并不慢,例如,
> system.time(split(seq_len(1300000), sample(250000, 1300000, TRUE)))
user system elapsed
1.056 0.000 1.058
所以如果你是我猜你的数据的某些方面会减慢速度,例如, ID
和code
都是具有许多级别的因素,因此它们的完整交互,而不是出现在你的数据集中的级别组合,是计算出来的
> length(split(1:10, list(factor(1:10), factor(10:1))))
[1] 100
> length(split(1:10, paste(letters[1:10], letters[1:10], sep="-")))
[1] 10
或者你的内存不足。
如果您在非 Windows 机器上使用进程,请使用mclapply
而不是parLapply
(我猜是这种情况,因为您要求detectCores()
)。
par_pop <- mclapply(idx, function(i, pop, fun) fun(pop[i,]), pop, func)
从概念上讲,这听起来像是您真正的目标是pvec
(在处理器上分配矢量化计算)而不是mclapply
(迭代数据框中的各个行)。
此外,实际上作为第一步,请考虑确定func
的瓶颈; 数据很大但不是那么大,所以也许不需要并行评估——也许你写的是 PDI 代码而不是 R 代码? 注意数据框中的数据类型,例如因子与字符。 在编写不佳的 R 代码和高效的 R 代码之间获得 100 倍的加速并不罕见,而并行评估最多与内核数量成正比。
如果 x 是一个因子并且 f 包含许多不同的元素,则 Split(x,f) 很慢
所以,这个代码如果很快:
system.time(split(seq_len(1300000), sample(250000, 1300000, TRUE)))
但是,这非常慢:
system.time(split(factor(seq_len(1300000)), sample(250000, 1300000, TRUE)))
这又快了,因为只有 25 个组
system.time(split(factor(seq_len(1300000)), sample(25, 1300000, TRUE)))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.