【问题标题】:Run a R function with multiple parameters in parallel mode以并行模式运行具有多个参数的 R 函数
【发布时间】:2014-11-10 09:56:14
【问题描述】:

我有这个功能

function1 <- function(df1, df2, int1, int2, char1)
{
...
return(newDataFrame)
}

有 5 个输入:前 2 个是数据帧,然后我有两个整数和一个字符串。 该函数返回一个新的数据框。

到目前为止,我正在依次运行此功能 8 次:

newDataFrame1 <- function1(df1, df2, 1, 1, "someString")
newDataFrame2 <- function1(df1, df2, 2, 0, "someString")
newDataFrame3 <- function1(df1, df2, 3, 0, "someString")
newDataFrame4 <- function1(df1, df2, 4, 0, "someString")
newDataFrame5 <- function1(df1, df2, 5, 0, "someString")
newDataFrame6 <- function1(df1, df2, 6, 0, "someString")
newDataFrame7 <- function1(df1, df2, 7, 0, "someString")
newDataFrame8 <- function1(df1, df2, 8, 0, "someString")

最后我使用 rbind() 组合结果:

newDataFrameTot <-  rbind(newDataFrame1, newDataFrame2, newDataFrame3, newDataFrame4, newDataFrame5, newDataFrame6, newDataFrame7, newDataFrame8)

我想使用 library(parallel) 并行运行它,但我无法弄清楚如何使它工作。我正在尝试:

cluster <- makeCluster(detectCores())
result <- clusterApply(cluster,1:8,function1)
newDataFrameTot <- do.call(rbind,result)

但这不起作用,除非我的函数 function1() 只有一个参数,我从 1 循环到 8。但这不是我的情况,因为我需要传递 5 个输入。 我怎样才能使这项工作并行?

【问题讨论】:

    标签: r performance parameters parallel-processing dataframe


    【解决方案1】:

    要遍历多个变量,clusterMap 非常有用。由于您只迭代 int1int2,您应该使用“MoreArgs”选项来指定您迭代的变量:

    cluster <- makeCluster(detectCores())
    clusterEvalQ(cluster, library(xts))
    result <- clusterMap(cluster, function1, int1=1:8, int2=c(1, rep(0, 7)),
                    MoreArgs=list(df1=df1, df2=df2, char1="someString"))
    df <- do.call('rbind', result)
    

    特别是,如果df1df2 是数据帧并且它们被指定为迭代变量而不是使用“MoreArgs”,clusterMap 将遍历这些数据帧的列而不是传递整个数据帧到function1,这不是你想要的。

    请注意,使用命名参数很重要,这样参数才能正确传递。


    性能说明

    如果 df1df2 非常大,您可以通过将它们导出到集群工作程序来获得更好的性能。这避免了在每个任务中发送它们,但需要一个包装函数。这也意味着您不再需要使用“MoreArgs”选项:

    clusterExport(cluster, c('df1', 'df2', 'function1'))
    wrapper <- function(int1, int2, char1) {
      function1(df1, df2, int1, int2, char1)
    }
    result <- clusterMap(cluster, wrapper, 1:8, c(1, rep(0, 7)), "someString")
    

    如果工人执行多个任务,这允许df1df2 被重用,但如果任务数等于工人数,则毫无意义。

    【讨论】:

    • 谢谢,试试这个。我收到一个错误,因为它说找不到“as.xts”函数。但是 library(xts) 是在 main 函数中指定的。
    • 我刚刚在并行调用的函数中添加了 library(xts)。我现在得到结果!谢谢。无论如何,每次迭代返回的数据帧然后水平连接,而我需要这些数据帧按行组合。到目前为止,我正在使用在每次迭代下调用函数后产生的每个单个数据帧的 rbind。是否可以告诉 clusterMap 按行组合?此外,为什么我不在组合结果中使用列名?不过谢谢你的帮助。
    • clusterMap 默认以列表的形式返回结果,与 clusterApply 的方式相同。您应该能够使用do.call('rbind', result) 组合结果。
    • 谢谢你现在一切正常。这很有帮助。
    【解决方案2】:

    要传递一个变量,您必须像您尝试过的那样使用lapplysapply 的并行版本。但是,要传递许多变量,您必须使用mapplyMap 的并行版本。那将是clusterMap,所以试试

    clusterMap(cluster, function1, df1, df2, 1:8, c(1, rep(0, 7)), "someString")
    

    编辑 正如 cmets 中所指出的,这将引发错误。通常,长度为 1 的参数(例如本例中的 "someString")应该被回收为其他长度的参数(例如本例中的 1:8)。抛出的错误是由于数据帧没有以相同的方式回收,而是被视为列表,因此它们的列是重复的,而不是整个数据帧。这就是为什么您收到错误$ operator is invalid for atomic vectors 的原因,因为在function1 内部,它试图在数据框的提取列 上使用$,这是一个向量,而不是数据框本身.对此有两种补救措施。第一个是在MoreArgs 中传递其他参数,如另一个答案中所述。这需要命名您的论点(无论如何这是一个好习惯)。解决它的第二种方法是将每个数据框包装在一个列表中:

    clusterMap(cluster, function1, list(df1), list(df2), 1:8, c(1, rep(0, 7)), "someString")
    

    这将起作用,因为现在整个数据帧 df1df2 将被回收。可以看到差异,例如通过查看rep(df1, 2)rep(list(df1), 2) 的输出。

    【讨论】:

    • 谢谢,我试过了,但出现错误:“checkForRemoteErrors(val) 中的错误:8 个节点产生错误;第一个错误:$ 运算符对原子向量无效”这里有什么问题?
    • 此消息是由于function1 内部发生的错误导致的,因此在不知道它看起来像什么的情况下很难分辨。您能否用函数的完整详细信息以及传递给它的参数更新您的帖子?
    • 我正在尝试使用一个工作示例进行更新。但是如何确定在我的 function1() 中抛出错误的阶段?
    • 如果您尝试为一组参数运行它,它可能会产生更有用的错误消息,或者您始终可以逐行浏览函数主体并查看错误发生的位置。 $ operator is invalid for atomic vectors 表示您正在使用 $ 访问向量的元素,而您应该在数据框或列表上使用它。因此,例如检查您有 object$variable 之类的行,并确保“对象”是数据框或列表?
    • 嗨,konvas,我在 function1 中看不到任何问题,事实上,当我按顺序运行时,一切正常,如帖子所示。当我尝试使用您建议的线路时,我遇到了这个问题。当我在 clusterMap() 中使用这些作为输入时,是否必须指定 df1 和 df2 是数据帧?
    【解决方案3】:

    由于我最近在 R 中遇到了同样的问题,所以我附上了一个非常有用的网站的链接。这是一个新的 multidplyr 包,可以在 R 中进行并行处理。它绝对适用于 Windows 10。:)

    http://www.business-science.io/code-tools/2016/12/18/multidplyr.html

    为了帮助您编写代码,这将是我建议的解决方案(没有测试,但应该可以像我在另一个示例中使用的那样工作)

    #Install the packages
    install.packages("devtools")
    devtools::install_github("hadley/multidplyr")
    require(multidplyr)
    library(parallel)
    cl <- detectCores()
    cluster <- create_cluster(cores = cl)
    cluster %>%
        # Assign libraries
        cluster_library("igraph") %>%
        cluster_library("tidyverse") %>%
        cluster_library("magrittr") %>%
        cluster_library("dplyr") %>%
        cluster_library("RColorBrewer") %>%
        # Assign values (use this to load functions or data to each core)
        cluster_assign_value("anyfunction", anyfunction)
    
    result <- clusterMap(cluster, function1, int1=1:8, int2=c(1, rep(0, 7)),
                MoreArgs=list(df1=df1, df2=df2, char1="someString"))
    

    【讨论】:

      猜你喜欢
      • 2019-07-18
      • 1970-01-01
      • 2017-02-18
      • 1970-01-01
      • 2013-08-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-13
      相关资源
      最近更新 更多