【问题标题】:Fast alternative to split in R在 R 中拆分的快速替代方案
【发布时间】:2013-10-03 00:08:42
【问题描述】:

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

【问题讨论】:

    标签: r split pentaho lapply


    【解决方案1】:

    将索引拆分为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 倍的加速并不罕见,而并行评估最多与内核数量成正比。

    【讨论】:

    • 谢谢,我试试。哈,实际上我最初是编写 R 代码,然后将其移植到 PDI(我对 R 的经验比对 PDI 的经验更丰富)。
    • 我运行了您发布的split() 代码,并等待了将近一个小时,但始终没有完成。
    • 围绕拆分添加了一些额外的建议,这应该花费大约一秒或更短的时间。也许因素也导致 func 也很慢?
    • 这对我很有帮助。长期以来,我一直在粘贴字符串的数据帧上盲目使用“拆分”,并且内存开销非常疯狂(data.frames 将 RAM 乘以 4x +)。这使我能够在 9 个内核而不是 2 个内核上运行我的代码,非常感谢。
    【解决方案2】:

    如果 x 是一个因子并且 f 包含许多不同的元素,则拆分 (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)))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-14
      • 1970-01-01
      • 1970-01-01
      • 2021-09-11
      相关资源
      最近更新 更多