Как преобразовать цикл for в цикл foreach в R? - PullRequest
1 голос
/ 04 апреля 2019

Я имею дело с проблемой, которая требует параллельных вычислений для получения более быстрых результатов, чем с классическим циклом for.

Вот проблема:

Мне нужно сгенерировать линейные модели для переменных результата 198135 года, содержащихся в кадрах данных в объекте списка. Я должен хранить все значения бета и p для каждой прогнозирующей переменной в моделях в кадре данных, а также их показатели соответствия.

Я написал функционал "for loop", который выполняет задачу должным образом, но для ее завершения требуется более 35 часов. Я знаю, что R использует менее 20% моего 8-ядерного процессора, и я хотел бы использовать все это. Проблема в том, что я не знаю, как преобразовать цикл for в цикл foreach для использования преимуществ параллельных вычислений.

Вот пример кода моей проблемы в меньшем масштабе:

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, потому что я не понимаю, что я делаю.

1 Ответ

0 голосов
/ 04 апреля 2019

Вы можете сделать:

## 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).

Learnбольше о том, как использовать foreach там .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...