在并行模式下运行具有多个参数的R函数

问题描述 投票:5回答:3

我有这个功能

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)

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

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

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

r performance parameters parallel-processing dataframe
3个回答
5
投票

要迭代多个变量,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,但如果任务数量等于工作人员数量则没有意义。


5
投票

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

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

编辑正如评论中指出的那样,这将引发错误。通常,长度为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)的输出。


0
投票

由于我最近在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"))
© www.soinside.com 2019 - 2024. All rights reserved.