【问题标题】:How to use Reduce() function in R parallel computing?如何在 R 并行计算中使用 Reduce() 函数?
【发布时间】:2016-10-04 19:46:09
【问题描述】:

我想将Reduce 代码运行到out1 66000 个列表元素的列表:

trialStep1_done <- Reduce(rbind, out1)

但是,运行时间太长。我想知道是否可以在并行计算包的帮助下运行此代码。

我知道有mclapplymcMap,但是我在并行计算包中没有看到像mcReduce这样的功能。

是否有类似 mcReduce 的函数可用于在 R 中并行执行 Reduce 以完成我想做的任务?

非常感谢@BrodieG 和@zheYuan Li,您的回答很有帮助。我认为下面的代码示例可以更准确地代表我的问题:

df1 <- data.frame(a=letters, b=LETTERS, c=1:26 %>% as.character())
set.seed(123)
df2 <- data.frame(a=letters %>% sample(), b=LETTERS %>% sample(), c=1:26 %>% sample() %>% as.character())
set.seed(1234)
df3 <- data.frame(a=letters %>% sample(), b=LETTERS %>% sample(), c=1:26 %>% sample() %>% as.character())
out1 <- list(df1, df2, df3)

# I don't know how to rbind() the list elements only using matrix()
# I have to use lapply() and Reduce() or do.call()
out2 <- lapply(out1, function(x) matrix(unlist(x), ncol = length(x), byrow = F))

Reduce(rbind, out2)
do.call(rbind, out2)
# One thing is sure is that `do.call()` is super faster than `Reduce()`, @BordieG's answer helps me understood why. 

所以,此时,对于我的 200000 行数据集,do.call() 很好地解决了问题。

最后,我想知道这是否是一种更快的方法?或者@ZheYuanLi 用matrix() 演示的方式在这里可以实现吗?

【问题讨论】:

    标签: r parallel-processing reduce


    【解决方案1】:

    问题不是rbind,问题是Reduce。不幸的是,R 中的函数调用很昂贵,尤其是当您不断创建新对象时。在这种情况下,您调用rbind 65999 次,每次您创建一个新的 R 对象并添加一行。相反,您可以使用 66000 个参数调用 rbind 一次,这将更快,因为在内部 rbind 将在 C 中进行绑定,而无需调用 R 函数 66000 次并且只分配一次内存。在这里,我们将您使用的Reduce 与哲元的矩阵/unlist 进行比较,最后将rbinddo.call 调用一次(do.call 允许您调用一个函数并将所有参数指定为列表):

    out1 <- replicate(1000, 1:20, simplify=FALSE)  # use 1000 elements for illustrative purposes
    
    library(microbenchmark)    
    microbenchmark(times=10,
      a <- do.call(rbind, out1),
      b <- matrix(unlist(out1), ncol=20, byrow=TRUE),
      c <- Reduce(rbind, out1)
    )
    # Unit: microseconds
    #                                                expr        min         lq
    #                           a <- do.call(rbind, out1)    469.873    479.815
    #  b <- matrix(unlist(out1), ncol = 20, byrow = TRUE)    257.263    260.479
    #                            c <- Reduce(rbind, out1) 110764.898 113976.376
    all.equal(a, b, check.attributes=FALSE)
    # [1] TRUE
    all.equal(b, c, check.attributes=FALSE)
    # [1] TRUE
    

    Zheyuan 是最快的,但就所有意图和目的而言,do.call(rbind()) 方法非常相似。

    【讨论】:

    • 非常感谢您对为什么do.callReduce 快得多的解释。它确实大大加快了速度!
    【解决方案2】:
    1. 速度很慢,因为您反复致电rbind。每次调用时,随着对象维度的增加,都必须进行新的内存分配。
    2. 您的工作受内存限制,您不会从并行性中受益。在多核机器上,并行处理仅对 CPU 密集型任务有用。

    如果我没有误会,你应该使用这个:

    trialStep1_done <- matrix(unlist(out1), nrow = length(out1), byrow = TRUE)
    

    例子:

    out1 <- list(1:4, 11:14, 21:24, 31:34)
    
    #> str(out1)
    #List of 4
    # $ : int [1:4] 1 2 3 4
    # $ : int [1:4] 11 12 13 14
    # $ : int [1:4] 21 22 23 24
    # $ : int [1:4] 31 32 33 34
    
    trialStep1_done <- matrix(unlist(out1), nrow = length(out1), byrow = TRUE)
    
    #> trialStep1_done
    #     [,1] [,2] [,3] [,4]
    #[1,]    1    2    3    4
    #[2,]   11   12   13   14
    #[3,]   21   22   23   24
    #[4,]   31   32   33   34
    

    感谢@BrodieG 的出色解释和基准测试结果!

    我也在我的笔记本电脑上尝试了基准测试,使用与 @BrodieG 完全相同的代码,这就是我得到的:

    Unit: microseconds
                                                   expr      min       lq      mean
                              a <- do.call(rbind, out1)   653.60   670.36   900.120
     b <- matrix(unlist(out1), ncol = 20, byrow = TRUE)   170.16   177.60   224.036
                               c <- Reduce(rbind, out1) 65589.48 67519.32 72317.812
       median       uq       max neval
       745.54   832.36   2352.28    10
       183.98   286.84    385.96    10
     68897.36 69372.88 108135.96    10
    

    【讨论】:

    • 感谢您的回答,尤其是对 parallel 部分的评论。我与您的评论相关的问题是:do.call(rbind, out2) 是否可以从并行性中受益,如果不是 Reduce(rbind, out2)
    • @Kenny,正如哲元所指出的,它们的潜在约束是内存的分配和复制。并行化可能会使这一切变得更慢,因为它需要更多的副本:首先,沿处理器拆分数据,然后在主线程中重新组合。
    • @BrodieG,谢谢。请允许我重新表述一下我从您和哲元的回答中收集到的内容。 1. 当我有大量计算或数学要做(需要大量 CPU)而不是大量拆分、复制和 rbind 数据对象(如 data.frame 或列表)时(需要大量记忆)。 2.在我的情况下,将大data.frame拆分为data.frame列表,并将data.frame列表转换为矩阵列表,将矩阵的rbind列表转换为单个矩阵,所有这些都是关于内存工作,而不是计算工作。 3.因此rbind与parallel没有任何关系
    • @Kenny,是的,差不多。如果你在那里的某个地方有一个长处理器密集型,那么并行化它可能是有意义的。
    猜你喜欢
    • 2018-06-06
    • 2020-04-27
    • 1970-01-01
    • 2020-09-14
    • 2022-11-14
    • 2021-09-06
    • 1970-01-01
    • 2018-08-24
    • 2019-06-13
    相关资源
    最近更新 更多