用mice R软件包并行计算多重插补

用mice R软件包并行计算多重插补,r,parallel-processing,r-mice,R,Parallel Processing,R Mice,我想使用R中的鼠标运行150次多重插补。然而,为了节省一些计算时间,我会撒谎将过程细分为并行流(正如Stef van Buuren在“缺失数据的灵活插补”中所建议的那样) 我的问题是:如何做到这一点 我可以想象两种选择: 备选案文1: imp1<-mice(data, m=1, pred=quicktry, maxit=15, seed=1) imp2<-mice(data, m=1, pred=quicktry, maxit=15, seed=1) imp...<-mice(

我想使用
R
中的
鼠标运行150次多重插补。然而,为了节省一些计算时间,我会撒谎将过程细分为并行流(正如Stef van Buuren在“缺失数据的灵活插补”中所建议的那样)

我的问题是:如何做到这一点

我可以想象两种选择:

备选案文1:

imp1<-mice(data, m=1, pred=quicktry, maxit=15, seed=1)
imp2<-mice(data, m=1, pred=quicktry, maxit=15, seed=1)
imp...<-mice(data, m=1, pred=quicktry, maxit=15, seed=1)
imp150<-mice(data, m=1, pred=quicktry, maxit=15, seed=1)
通过将
VAL_1添加到150
否则,在我看来(我可能错了),如果它们都使用相同的数据集和相同的种子运行,您将得到150倍相同的结果

还有其他选择吗


谢谢

所以主要的问题是合并插补,在我看来有三种选择,使用
ibind
如前所述完成
,或者尝试保持mids结构。我强烈建议使用
ibind
解决方案。其他的答案留给那些好奇的人

获得并行结果 在做任何事情之前,我们需要得到平行的老鼠插补。并行部分相当简单,我们需要做的就是使用并行包,并确保使用
clusterSetRNGStream
设置种子:

library(parallel)
# Using all cores can slow down the computer
# significantly, I therefore try to leave one
# core alone in order to be able to do something 
# else during the time the code runs
cores_2_use <- detectCores() - 1

cl <- makeCluster(cores_2_use)
clusterSetRNGStream(cl, 9956)
clusterExport(cl, "nhanes")
clusterEvalQ(cl, library(mice))
imp_pars <- 
  parLapply(cl = cl, X = 1:cores_2_use, fun = function(no){
    mice(nhanes, m = 30, printFlag = FALSE)
  })
stopCluster(cl)
使用
foreach
ibind
也许最简单的替代方法是使用
foreach

library(foreach)
library(doParallel)
cl <- makeCluster(cores_2_use)
clusterSetRNGStream(cl, 9956)
registerDoParallel(cl)

library(mice)
imp_merged <-
  foreach(no = 1:cores_2_use, 
          .combine = ibind, 
          .export = "nhanes",
          .packages = "mice") %dopar%
{
  mice(nhanes, m = 30, printFlag = FALSE)
}
stopCluster(cl)
给出输出:

                    est         se         est         se
(Intercept) 20.41921496 3.85943925 20.33952967 3.79002725
age         -3.56928102 1.35801557 -3.65568620 1.27603817
hyp          1.63952970 2.05618895  1.60216683 2.17650536
chl          0.05396451 0.02278867  0.05525561 0.02087995
保持正确的mids对象 下面我的另一种方法展示了如何合并插补对象并保留
mids
对象背后的全部功能。自从使用了
ibind
解决方案后,我就把这个留给了任何有兴趣探索如何合并复杂列表的人

我已经研究了
鼠标
的mids对象,为了在并行运行后获得至少一个类似的mids对象,您必须采取一些步骤。如果我们检查mids对象并比较两个具有两种不同设置的对象,我们会得到:

library(mice)
imp <- list()
imp <- c(imp,
         list(mice(nhanes, m = 40)))
imp <- c(imp,
         list(mice(nhanes, m = 20)))

sapply(names(imp[[1]]),
       function(n)
         try(all(useful::compare.list(imp[[1]][[n]], 
                                      imp[[2]][[n]]))))
给出:

                    est         se         est        se
(Intercept) 20.16057550 3.74819873 20.31814393 3.7346252
age         -3.67906629 1.19873118 -3.64395716 1.1476377
hyp          1.72637216 2.01171565  1.71063127 1.9936347
chl          0.05590999 0.02350609  0.05476829 0.0213819
                    est         se
(Intercept) 20.14271905 3.60702992
age         -3.78345532 1.21550474
hyp          1.77361005 2.11415290
chl          0.05648672 0.02046868

好了,就这样。玩得开心。

我想你没有答案的原因是你的问题太宽泛,不够具体。关于使用R进行并行处理的主题,有很多参考资料。请尝试构建一些实现您的选项的代码,如果遇到问题,请发布一个更具体的问题。分割本身并不能节省计算时间。您需要研究并行化包,例如
parallel
snow
multicore
。然而,了解这些工作将花费的时间可能比你通过插补节省的时间要多。你仍然对答案感兴趣吗?@SimonG:从实现方面来说并不难,我想说,最具挑战性的部分是知道什么是并行化,以及如何在应用数据方面进行并行化。我最近实现了Emanuela想要做的事情,我对结果非常满意。你可以在我的回答中读到更多:。是的,Aleksandr,我仍然感兴趣!我一定会尝试你建议的程序。仅供参考:我认为你可以通过使用
鼠标
ibind()
而不是你的
mergemices()
:。谢谢@AleksandrBlekh-我已经添加了这个作为推荐解决方案。我没有第一眼就找到它,真烦人。我的荣幸!我也没有立即注意到这一点——有人向我指出了这种方法。顺便说一句,在添加引用时,您在整个答案中键入了函数名(代码块除外)-它是
ibind
。这是一个很好的答案--我都将其向上投票并保存到Evernote--但我在第一个解决方案中遇到了问题。我有一个45000x64数据集,丢失率约为5%。作为测试,在m=1的4核2.5GHz笔记本电脑上运行解决方案第一部分的代码大约需要20分钟。在具有24个相同速度内核的服务器上运行相同的代码需要两倍的时间。我哪里做错了?我用m=30试过了,但两个小时后,我不得不把它杀死,因为我没有足够的时间去看它需要多长时间才能完成。@Hack-R:根据我的经验,这是因为缺乏记忆。如果运行到最大内存,Windows计算机将在Linux计算机崩溃时开始交换(虚拟暂停)。我最近写了一篇关于并行化的博文:我建议您尝试减少数据集中的列数(如果可能的话),或者将插补的数据集保存到文件中,返回文件名,执行
rm(imp_数据);gc()然后在插补后加载文件。
                    est         se         est         se
(Intercept) 20.41921496 3.85943925 20.33952967 3.79002725
age         -3.56928102 1.35801557 -3.65568620 1.27603817
hyp          1.63952970 2.05618895  1.60216683 2.17650536
chl          0.05396451 0.02278867  0.05525561 0.02087995
library(mice)
imp <- list()
imp <- c(imp,
         list(mice(nhanes, m = 40)))
imp <- c(imp,
         list(mice(nhanes, m = 20)))

sapply(names(imp[[1]]),
       function(n)
         try(all(useful::compare.list(imp[[1]][[n]], 
                                      imp[[2]][[n]]))))
mergeMice <- function (imp) {
  merged_imp <- NULL
  for (n in 1:length(imp)){
    if (is.null(merged_imp)){
      merged_imp <- imp[[n]]
    }else{
      counter <- merged_imp$m
      # Update counter
      merged_imp$m <- 
        merged_imp$m + imp[[n]]$m
      # Rename chains
      dimnames(imp[[n]]$chainMean)[[3]] <-
        sprintf("Chain %d", (counter + 1):merged_imp$m)
      dimnames(imp[[n]]$chainVar)[[3]] <-
        sprintf("Chain %d", (counter + 1):merged_imp$m)
      # Merge chains
      merged_imp$chainMean <- 
        abind::abind(merged_imp$chainMean, 
                     imp[[n]]$chainMean)
      merged_imp$chainVar <- 
        abind::abind(merged_imp$chainVar, 
                     imp[[n]]$chainVar)
      for (nn in names(merged_imp$imp)){
        # Non-imputed variables are not in the
        # data.frame format but are null
        if (!is.null(imp[[n]]$imp[[nn]])){
          colnames(imp[[n]]$imp[[nn]]) <- 
            (counter + 1):merged_imp$m
          merged_imp$imp[[nn]] <- 
            cbind(merged_imp$imp[[nn]],
                  imp[[n]]$imp[[nn]])
        }
      }
    }
  }
  # TODO: The function should update the $call parameter
  return(merged_imp)
}
merged_imp <- mergeMice(imp)
merged_imp_pars <- mergeMice(imp_pars)
# Compare the three alternatives
cbind(
  summary(pool(with(data=merged_imp,
                    exp=lm(bmi~age+hyp+chl))))[,c("est", "se")],
 summary(pool(with(data=merged_imp_pars,
                    exp=lm(bmi~age+hyp+chl))))[,c("est", "se")],
 summary(pool(with(data=mice(nhanes, 
                             m = merged_imp$m, 
                             printFlag = FALSE),
                   exp=lm(bmi~age+hyp+chl))))[,c("est", "se")])
                    est         se         est        se
(Intercept) 20.16057550 3.74819873 20.31814393 3.7346252
age         -3.67906629 1.19873118 -3.64395716 1.1476377
hyp          1.72637216 2.01171565  1.71063127 1.9936347
chl          0.05590999 0.02350609  0.05476829 0.0213819
                    est         se
(Intercept) 20.14271905 3.60702992
age         -3.78345532 1.21550474
hyp          1.77361005 2.11415290
chl          0.05648672 0.02046868