r - 如何在 R 的“foreach”循环中转换“for 循环”?
问题描述
我正在处理一个需要并行计算才能获得比经典“for 循环”更快的结果的问题。
这是问题所在:
我需要为列表对象内的数据框中包含的 198135 个结果变量生成线性模型。我必须将模型中每个预测变量的所有 beta 值和 p 值存储在数据框中,以及它们的拟合优度度量。
我编写了一个功能性的“for 循环”,可以正确完成任务,但完成它需要 35 多个小时。我知道 R 使用的 8 核 CPU 不到 20%,我想全部使用它。问题是我不知道如何在 foreach 循环中转换我的 for 循环以利用并行计算。
这是我的问题的一些较小规模的示例代码:
library(tidyverse)
library(broom)
## Example data
outcome_list <- list(as.data.frame(cbind(rnorm(32), dataframe_id = c(1))),
as.data.frame(cbind(rnorm(32), dataframe_id = c(2))),
as.data.frame(cbind(rnorm(32), dataframe_id = c(3)))) ## This represents my list of 198135 dataframes
mtcars <- mtcars #I will use the explanatory variables from here
## Below this line is my current solution with a for loop that works fine
x <- list()
results_df <- as.data.frame(cbind(dataframe_id = c(0), intercept = c(0),
b_mpg = c(0), p_mpg = c(0),
b_cyl = c(0), p_cyl = c(0),
p.model = c(0), AIC = c(0),
BIC = c(0)))
for(i in 1:3){
x[[i]] <- lm(outcome_list[[i]]$V1 ~ mtcars$mpg + mtcars$cyl)
gof <- broom::glance(x[[i]])
betas <- broom::tidy(x[[i]])
results_df <- rbind(results_df, c(outcome_list[[i]]$V2[1],
betas$estimate[1],
betas$estimate[2], betas$p.value[2],
betas$estimate[3], betas$p.value[3],
gof$p.value, gof$r.squared, gof$AIC,
gof$BIC))
if(i %% i == 0){
message(paste(i, "of 3")) # To know if my machine has not crashed
x <- list() # To keep RAM clean of useless data
}
gc()
}
results_df <- results_df[-1, ]
使用上面显示的代码,我得到了我需要的结果(具有回归参数的数据框和列表中每个结果变量的拟合优度),但它非常慢,因为我无法使用我所有的计算机能力。
我知道使用“foreach”和“doParallel”包可以更快地解决这个问题,但我仍然不明白 foreach 循环结构背后的逻辑,因为这是我第一次需要处理这么多数据。
PS:我已经尝试了几种使用 foreach 函数的方法,但我没有得到任何结果。我没有写我的 foreach 尝试解决方案,因为我不明白我在做什么。
解决方案
你可以做:
## Example data
outcome_list <- list(as.data.frame(cbind(rnorm(32), dataframe_id = c(1))),
as.data.frame(cbind(rnorm(32), dataframe_id = c(2))),
as.data.frame(cbind(rnorm(32), dataframe_id = c(3))))
## Parallel code
library(doParallel)
registerDoParallel(cl <- makeCluster(3))
results_list <- foreach(i = 1:3) %dopar% {
mylm <- lm(outcome_list[[i]]$V1 ~ mtcars$mpg + mtcars$cyl)
gof <- broom::glance(mylm)
betas <- broom::tidy(mylm)
c(outcome_list[[i]]$V2[1],
betas$estimate[1],
betas$estimate[2], betas$p.value[2],
betas$estimate[3], betas$p.value[3],
gof$p.value, gof$r.squared, gof$AIC,
gof$BIC)
}
stopCluster(cl)
results_df <- setNames(as.data.frame(do.call("rbind", results_list)),
c("dataframe_id", "intercept", "b_mpg", "p_mpg",
"b_disp", "p_disp", "p.model", "AIC", "BIC"))
你在 foreach 中返回你的结果(就像 lapply 一样)而不是增长一个对象(这在并行 BTW 中是不可能的)。
在此处了解有关如何使用 foreach 的更多信息。
推荐阅读
- php - 使用 queryBuidler 运行 get() 时,stdClass 类的对象无法转换为字符串
- docker - 在 docker 容器中运行时找不到 Sendmail 主机
- python - 用三个条件删除重复项,Pandas
- r - 具有多个参数的 R 双积分
- javascript - 反应 - 没有返回
- ruby-on-rails - 带有表单对象的 Simple_form 缺少映射
- java - 使用 Java 8 Streams 对 Map 的值(Set -> SortedSet)进行排序
- anylogic - AnyLogic中的随机
- javascript - 在javascript中解析本地文件中的特定内容?
- javascript - 通过 JS 向 CSS 类添加 url 链接