Foreach和doparallel而不是R中的for循环

Posted

技术标签:

【中文标题】Foreach和doparallel而不是R中的for循环【英文标题】:Foreach and doparallel instead of for loop in R 【发布时间】:2020-07-13 06:05:18 【问题描述】:

我需要通过多线程加速 for 循环。我想为此使用库:foreachdoParallel。我以前使用过这些包,但仅用于需要一个结果表的过程。我不知道如何使用它们来导出多个表(这里是结果表)。我的问题要复杂得多,需要导出许多结果集。在这里,为简单起见,我使用虹膜数据。

library(randomForest)
library(caret)

results_class <- data.frame()
results_overall <- data.frame()

for(i in 1:50)
  trainIndex <- caret::createDataPartition(iris$Species, p = 0.5, list = FALSE)
  irisTrain <- iris[ trainIndex,]
  irisTest  <- iris[-trainIndex,]

  model <- randomForest(x = irisTrain[,c(1:4)], y = irisTrain[,5], importance = TRUE,
                        replace = TRUE, mtry = 4, ntree = 500, na.action=na.omit,
                        do.trace = 100, type = "classification")

  pred_test <- predict(model, irisTest[,c(1:4)])
  con.mat_test <- confusionMatrix(pred_test, irisTest[,5], mode ="everything")

  results_class <- rbind(results_class, con.mat_test[["byClass"]])
  results_overall <- rbind(results_overall, con.mat_test[["overall"]])


【问题讨论】:

我知道.multicombine 与单个.combine 结合使用。 首先,确保更新到 foreach 1.5.0(2020 年 3 月 30 日发布),因为它使顺序和并行进程在 local() 环境中评估 foreach 表达式。这进一步降低了错误/误解的风险,尤其是“希望”在循环内完成的任务最终在外面 - 他们不能也不会(也不应该) 其次,请参阅我 2019 年 1 月 11 日的博客文章“通过将 For-Loop 重写为 Lapply 调用来并行化 For-Loop”(jottr.org/2019/01/11/…),了解如何将 for 循环转换为 ay 【参考方案1】:

据我所知,在foreach 循环之外修改变量并不容易(甚至不可能),那么将多个结果存储在一个嵌套的tibble 中呢?

library(randomForest)
library(caret)
library(foreach)
library(doParallel)

# Set up parallel computing
cl <- makeCluster(detectCores(logical = TRUE))
registerDoParallel(cl)

res <- foreach(i = 1:50, .packages = c("caret", "randomForest"), .combine = rbind) %dopar% 
    trainIndex <- caret::createDataPartition(iris$Species, p = 0.5, list = FALSE)
    irisTrain <- iris[ trainIndex,]
    irisTest  <- iris[-trainIndex,]

    model <- randomForest(x = irisTrain[,c(1:4)], y = irisTrain[,5], importance = TRUE,
                          replace = TRUE, mtry = 4, ntree = 500, na.action=na.omit,
                          do.trace = 100, type = "classification")

    pred_test <- predict(model, irisTest[,c(1:4)])
    con.mat_test <- confusionMatrix(pred_test, irisTest[,5], mode ="everything")

    # Save class into separate variable
    # Use substr to get rid of "Class: "
    class <- data.frame(con.mat_test[["byClass"]])
    overall <- data.frame(con.mat_test[["overall"]])
    class$class <- sapply(rownames(class), function(x) substr(x, 8, nchar(x)))
    overall$class <- sapply(rownames(overall), function(x) substr(x, 8, nchar(x)))

    # Save output dataframe in tibble as list column
    return(tibble::tibble(iteration = i, 
                          class = list(class), 
                          overall = list(overall)))


# Stop the cluster
stopCluster(cl)
registerDoSEQ()

然后输出如下:

> print(res)
# A tibble: 50 x 3
   iteration class              overall         
       <int> <list>             <list>          
 1         1 <df[,12] [3 x 12]> <df[,2] [7 x 2]>
 2         2 <df[,12] [3 x 12]> <df[,2] [7 x 2]>
 3         3 <df[,12] [3 x 12]> <df[,2] [7 x 2]>
 4         4 <df[,12] [3 x 12]> <df[,2] [7 x 2]>
 5         5 <df[,12] [3 x 12]> <df[,2] [7 x 2]>
 6         6 <df[,12] [3 x 12]> <df[,2] [7 x 2]>
 7         7 <df[,12] [3 x 12]> <df[,2] [7 x 2]>
 8         8 <df[,12] [3 x 12]> <df[,2] [7 x 2]>
 9         9 <df[,12] [3 x 12]> <df[,2] [7 x 2]>
10        10 <df[,12] [3 x 12]> <df[,2] [7 x 2]>
# ... with 40 more rows

【讨论】:

谢谢。如何将这些结果转换为我最初想要的那些表格? 我不知道您正在寻找什么结果,但您可以通过使用简单的子集(例如res$class)来获取表格列表。要获得一张桌子,您可以使用tidyr::unnest(res, class)dplyr::bind_rows(res$class) 我更仔细地检查了它,如果我们在完成后查看数据框: unnest_dataset 是的,你是对的。那是因为(出于某种原因)我将每次迭代的结果添加到results_overallresults_class。由于此循环分布在多个工作人员上,因此每个结果都与该工作人员上一次迭代的结果一起存储。解决方案是简单地不结合它。我已更新我的答案以反映这一点。 行名仍然存在。试试res$class[[1]],你会发现它们还在。问题在于unnest 将新行绑定到现有数据的方式,而忽略了行名,因为否则它们会重复。一种解决方案是将classoverall 数据帧中的类保存在单独的变量中。我已经更新了我的答案以反映这一点。

以上是关于Foreach和doparallel而不是R中的for循环的主要内容,如果未能解决你的问题,请参考以下文章

R doParallel foreach 中的并行处理

在 R 中将 fread 与 foreach 和 doParallel 一起使用

使用 foreach 函数和 doParallel 库在 R 中嵌套 for 循环

R doParallel foreach 对独立工作者进行错误处理

在 R doParallel foreach 循环中运行 ovun.sample

在 R 中使用 doParallel 的 foreach 时,Windows Defender 的 CPU 使用率非常高