在使用doMC进行并行仿真研究时,需要关于组合函数的帮助



我想请求一些帮助来编写foreach()的组合函数。考虑下面的函数:

library(mvtnorm)
library(doMC)
mySimFunc <- function(){
  myNum <- runif(1)
  myVec <- rnorm(10)
  myMat <- rmvnorm(5, rep(0, 3), diag(3))
  myListRslt <- list("myNum" = myNum, "myVec" = myVec, "myMat" = myMat)
return (myListRslt)
}

现在我想使用foreach() %dopar%运行上述代码1000次,并且在每次迭代中我想:

  1. 返回myNum为
  2. 获取myVec的平均值并返回
  3. 获取myMat的colMeans()并返回。

我希望foreach() %dopar%返回一个最终列表,包括:

  1. 一个长度为1000的向量,包含1000个myNum,每个myNum对应一个迭代
  2. 长度为1000的向量,包含每次迭代中myVec的1000个平均值
  3. 包含1000行的矩阵,其中每行包含该迭代中myMat的colMeans

My Ideal solution

我的理想解决方案是找到一种方法,foreach()的行为完全像for,这样我就可以简单地定义:

myNumRslt <- NULL
myVecRslt <- NULL
myMatRslt <- NULL
# and then simply aggregate result of each iteration to the variables above as:
foreach(i = 1:1000) %dopar%{
   rslt <- mySimFunc()
   myNumRslt <- c(myNumRslt, rslt$myNum)
   myVecRslt <- c(myVecRslt, mean(rslt$myVec))
   myMatRslt.tmp <- colMeans(rslt$myMat)
   myMatRslt <- rbind(myMatRslt, myMatRslt.tmp)
}

但是,不幸的是,似乎不可能用foreach()做到这一点,所以我认为唯一的解决方案是编写一个组合函数,类似于上面的结果聚合。

1)我怎么能写一个组合函数返回我上面解释的?

2)当我们做%dopar%(假设使用doMC包)时,doMC是将每个迭代分发到一个CPU上,还是进一步将每个迭代划分为进一步的部分并分发它们?

3)是否有比使用doMC和foreach()更好(更有效)的方法?想法的在这个问题中,Brian提到了一种处理包含数值的列表的绝妙方法。在我的例子中,我有数值以及向量和矩阵。我不知道如何在我的情况下推广布莱恩的想法。

非常感谢您的帮助

编辑

使用.combine:

清理,可推广的解决方案
#modify function to include aggregation
mySimFunc2 <- function(){
myNum <- runif(1)
myVec <- mean(rnorm(10))
myMat <- colMeans(rmvnorm(5, rep(0, 3), diag(3)))
myListRslt <- list("myNum" = myNum, "myVec" = myVec, "myMat" = myMat)
return (myListRslt)
}
#.combine function
MyComb1 <- function(...) {
lst=list(...)
vec<-sapply(1:length(lst), function (i) return(lst[[i]][[1]] ))
vecavg<-sapply(1:length(lst),function (i) return(lst[[i]][[2]] ))
colmeans<-t(sapply(1:length(lst), function (i) return(lst[[i]][[3]])))
final<-list(vec,vecavg,colmeans)
names(final)<-c("vec","vecavg","colmeans")
return(final)
}
library(doParallel)
cl <- makeCluster(3) #set cores
registerDoParallel(cl)
foreach(i=1:1000,.export=c("mySimFunc2","MyComb1"),.combine=MyComb1,
.multicombine=TRUE,.maxcombine=1000, .packages=c("mvtnorm"))%dopar%{mySimFunc2()}

您现在应该有一个包含所需三个对象的列表输出,我分别将其命名为vec, vecavgcolmeans。注意,如果迭代次数大于100,则必须将.maxcombine设置为迭代次数。

作为旁注,对这个示例任务并行化是没有意义的,尽管我猜真正的任务可能更复杂。

最新更新