首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >利用mice R软件包并行计算多重插值

利用mice R软件包并行计算多重插值
EN

Stack Overflow用户
提问于 2014-06-04 22:31:10
回答 1查看 8.1K关注 0票数 18

我想通过在R中使用mice来运行150次多重估算。然而,为了节省一些计算时间,我建议将进程细分为并行流(如Stef van Buuren在"Flexible Imputation for Missing Data“中所建议的那样)。

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

我可以想象有两种选择:

选项1:

代码语言:javascript
复制
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)

然后使用completeas.mids将计算结果组合在一起

选项2:

代码语言:javascript
复制
imp1<-mice(data, m=1, pred=quicktry, maxit=15, seed=VAL_1to150)
imp2<-mice(data, m=1, pred=quicktry, maxit=15, seed=VAL_1to150)
imp...<-mice(data, m=1, pred=quicktry, maxit=15, seed=VAL_1to150)
imp150<-mice(data, m=1, pred=quicktry, maxit=15, seed=VAL_1to150)

通过添加VAL_1to150,否则在我看来(我可能是错的),如果它们都使用相同的数据集和相同的种子运行,您将得到150倍相同的结果。

还有没有别的选择?

谢谢

EN

回答 1

Stack Overflow用户

发布于 2014-11-23 18:10:58

所以主要的问题是组合这些估算,在我看来,有三种选择,使用所描述的ibindcomplete或者尝试保持mids结构。我强烈建议使用ibind解决方案。对于那些好奇的人,剩下的就留在答案里了。

获取并行结果

在做任何事情之前,我们需要得到平行小鼠的估算。并行部分相当简单,我们需要做的就是使用parallel包,并确保我们使用clusterSetRNGStream设置种子

代码语言:javascript
复制
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)

以上将产生cores_2_use * 30估算的数据集。

使用ibind

正如@AleksanderBlekh所建议的,mice::ibind可能是最好、最直接的解决方案:

代码语言:javascript
复制
imp_merged <- imp_pars[[1]]
for (n in 2:length(imp_pars)){
  imp_merged <- 
    ibind(imp_merged,
          imp_pars[[n]])
}

ibind中使用foreach

也许最简单的替代方法是使用foreach

代码语言:javascript
复制
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)

使用complete

使用complete(..., action="long")rbind-ing这些方法提取完整的数据集,然后使用as.mids other mice对象可能工作得很好,但它生成的对象比其他两种方法更精简:

代码语言:javascript
复制
merged_df <- nhanes
merged_df <- 
  cbind(data.frame(.imp = 0,
                   .id = 1:nrow(nhanes)),
        merged_df)
for (n in 1:length(imp_pars)){
  tmp <- complete(imp_pars[[n]], action = "long")
  tmp$.imp <- as.numeric(tmp$.imp) + max(merged_df$.imp)
  merged_df <- 
    rbind(merged_df,
          tmp)
}

imp_merged <- 
  as.mids(merged_df)

# Compare the most important the est and se for easier comparison
cbind(summary(pool(with(data=imp_merged,
                        exp=lm(bmi~age+hyp+chl))))[,c("est", "se")],
      summary(pool(with(data=mice(nhanes, 
                                  m = 60, 
                                  printFlag = FALSE),
                        exp=lm(bmi~age+hyp+chl))))[,c("est", "se")])

给出输出:

代码语言:javascript
复制
                    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-object

下面我的替代方法展示了如何合并补偿对象并保留mids对象背后的全部功能。自从有了ibind解决方案后,我就把这篇文章留给了对探索如何合并复杂列表感兴趣的任何人。

我已经研究了mice的mids-object,为了在并行运行后至少获得一个类似的mids-object,你必须采取一些步骤。

代码语言:javascript
复制
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]]))))

其中您可以看到,两次运行之间的call、m、imp、chainMean和chainVar是不同的。在这些组件中,imp无疑是最重要的,但它似乎也是更新其他组件的明智选择。因此,我们将首先构建一个mice合并函数:

代码语言:javascript
复制
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)
}

我们现在可以通过以下方式简单地合并上面生成的两个估算:

代码语言:javascript
复制
merged_imp <- mergeMice(imp)
merged_imp_pars <- mergeMice(imp_pars)

现在,我们似乎得到了正确的输出:

代码语言:javascript
复制
# 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")])

提供:

代码语言:javascript
复制
                    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

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

票数 34
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24040280

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档