在使用doMC的并行仿真研究中需要有关组合功能的帮助

时间:2014-05-05 05:57:30

标签: r foreach parallel-processing 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()并将其返回。
  4. 我希望foreach()%dopar%返回最终列表,包括:

    1. 长度为1000的向量,包括1000个myNum,每个对应于一次迭代
    2. 长度为1000的向量,包括每次迭代中1000个myVec的平均值
    3. 一个包含1000行的矩阵,其中每行包含该迭代中myMat的colMeans
    4. 我的理想解决方案

      我理想的解决方案是找到foreach()的行为方式,以便我可以简单地定义:

      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()更好(更有效)的方法? 的主意&#39; S 在此question Brian中提到了处理包括数值的列表的绝妙方法。就我而言,我有数值以及向量和矩阵。在我的案例中,我不知道如何扩展Brian的想法。

      非常感谢你的帮助。

1 个答案:

答案 0 :(得分:1)

修改

使用.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()}

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

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