【问题标题】:Faster alternative to split-apply-combine拆分应用组合的更快替代方案
【发布时间】:2014-08-15 06:31:03
【问题描述】:

短版

Split-apply-combine 与 plyr::dlply 似乎效率低下,因为拆分和合并需要开销。我错了,还是有更好/更快的方法?


长版

我在 R 中使用一个类似于 vars::VAR 的美化包装器/提取器的函数来拟合数千个向量自回归。我就叫它estim

现在,我的数据是“长”格式,例如

dd <- structure(list(id = c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 3L, 3L, 
3L, 3L), time = c(1L, 2L, 3L, 4L, 1L, 2L, 3L, 4L, 1L, 2L, 3L, 
4L), x = c(0L, 0L, 1L, 0L, 6L, 2L, 3L, 2L, 3L, 3L, 1L, 1L), y = c(0L, 
1L, 1L, 0L, 2L, 0L, 2L, 0L, 0L, 3L, 3L, 0L)), .Names = c("id", 
"time", "x", "y"), row.names = c(NA, -12L), class = "data.frame")

我正在使用output &lt;- plyr::dlply(dd, .(id), myFun) 处理。

有了大约 4,800 个唯一 ID,每个 ID 有 182 个时间点,我得到了

system.time(output <- plyr::dlply(dd, .(id), estimate, .parallel = FALSE))
#   user  system elapsed 
# 37.357   0.730  38.048 

registerDoMC(detectCores() - 1) # I have 4 cores
system.time(output <- plyr::dlply(dd, .(id), estimate, .parallel = TRUE))
#   user  system elapsed 
# 57.234   6.710  23.593 

在我的 MacBook(2.8 GHz i7 和 16 GB RAM)上。

并行执行并没有像我希望的那样节省时间。这向我表明,此操作的“慢”部分不在于计算 estimate,而在于 dplyr 采用的拆分和组合步骤。

split-apply-combine 范式非常适合交互式和中等规模的使用(至少在这种情况下比循环快得多),但我怀疑还有更好的方法。我是否应该将数据重塑为“宽”格式,例如

dd.wide <- structure(list(time = 1:4, `1_x` = c(0L, 0L, 1L, 0L), `1_y` = c(0L, 
1L, 1L, 0L), `2_x` = c(6L, 2L, 3L, 2L), `2_y` = c(2L, 0L, 2L, 
0L), `3_x` = c(3L, 3L, 1L, 1L), `3_y` = c(0L, 3L, 3L, 0L)), .Names = c("time", 
"1_x", "1_y", "2_x", "2_y", "3_x", "3_y"), row.names = c(NA, 
-4L), class = "data.frame")

然后将myFun 应用于成对的列?

有没有更有效的方法来实现这一点?或者,我可以在这里更好地利用并行化吗?还是会达到预期的速度?

最后,让我们说现在我想做的事

estim2 <- function(param) ddply(dd, .(id), estim, foo = param)
output.list <- lapply(1:10, estim2)

答案是否完全改变?我对并行化这种嵌套循环的“正确”方法特别感兴趣,尽管我确信这个网站之前已经介绍过。

【问题讨论】:

  • "dplyr 使用的拆分和组合步骤" 用 dplyr 而不是 plyr(您现在正在使用的软件包)尝试这个怎么样?我更喜欢 data.table,但 dplyr is 比 plyr 快得多。如果您要求性能建议,您应该提供可重现的代码并创建您正在处理的规模的数据。
  • @Roland: + 1 for data.table
  • 我也喜欢 data.table(和 dplyr),但我可以让它返回一个任意列表吗?我对两者都很陌生。
  • 让你的问题成为一个可重复的例子,我估计你会在 15 分钟内知道你是否可以做你想做的事(以及可能如何以不同的方式完成) )。
  • 正如@Roland 和其他人所指出的,您的答案完全取决于您使用的功能。在 4 个内核上获得 2 倍的加速听起来是合理的,因为至少有一部分时间花在了内核之间的通信和整理结果的开销上。您目前的解决方案每个 id 大约需要 5 微秒。你希望它快多少?无论如何,这个级别的微调取决于减少流程每个步骤的低效率。发布一个完全可重现的示例。

标签: r performance data-structures plyr


【解决方案1】:

根据 cmets,我对开销的怀疑是错误的。内部函数的执行时间约为 7 微秒,0.007 * 4800 = 33.6 秒。

所以关于:

Split-apply-combine 与 plyr::dlply 似乎效率低下,因为拆分和合并需要开销。我错了,还是有更好/更快的方法?

答案是这样的

如果不加快内部函数的速度,期望大幅加速可能是不合理的。

事实上,我错了。

【讨论】:

    猜你喜欢
    • 2013-10-03
    • 1970-01-01
    • 2018-12-11
    • 2012-07-05
    • 2012-01-23
    • 2013-07-13
    • 2011-02-27
    • 2010-09-22
    相关资源
    最近更新 更多