快速替代R分裂

时间:2013-09-26 20:31:58

标签: r split pentaho lapply

我正在使用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,但它也跑了一个多小时但从未完成。

2 个答案:

答案 0 :(得分:10)

将索引拆分为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 

所以,如果你的,我猜你的数据的某些方面会降低速度,例如,IDcode都是具有多个级别的因素,因此它们完全相互作用,而不是级别组合出现在您的数据集中,计算

> 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代码之间获得100倍的加速并不罕见,而并行评估最多与内核数量成正比。

答案 1 :(得分:3)

如果x是因子,则分割(x,f)很慢并且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)))