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

时间:2014-11-10 09:56:14

标签: r performance parameters parallel-processing dataframe

我有功能

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个输入。 我怎样才能并行完成这项工作?

3 个答案:

答案 0 :(得分: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) vs rep(list(df1), 2)的输出。

答案 1 :(得分: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重复使用,但如果任务数量等于工作人员数量则无意义。

答案 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"))