Использование foreach вместо цикла for

Я пытаюсь научиться foreach распараллеливать свою задачу

Мой цикл for выглядит так:

     # create an empty matrix to store results
     mat <- matrix(-9999, nrow = unique(dat$mun), ncol = 2)

     for(mun in unique(dat$mun)) {

           dat <- read.csv(paste0("data",mun,".csv")
           tot.dat <- sum(dat$x)
           mat[mat[,1]== mun,2] <- tot.dat
     }

unique(dat$mun) имеет длину 5563.

Я хочу использовать foreach для параллелизма моей задачи.

      library(foreach)
      library(doParallel)

      # number of iterations
      iters <- 5563

      foreach(icount(iters)) %dopar% {
          mun <- unique(dat$mun)[mun] # this is where I cannot figure out how to assing mun so that it read the data for mun

          dat <- read.csv(paste0("data",mun,".csv")
          tot.dat <- sum(dat$x)
          mat[mat[,1]== mun,2] <- tot.dat
        }

person 89_Simple    schedule 14.02.2018    source источник
comment
Вы читали виньетки на упаковке? Циклы foreach принципиально отличаются от циклов for. Самое главное, они не могут иметь побочных эффектов (по крайней мере, при использовании для распараллеливания). Это означает, что вы не можете присваивать объекту вне цикла (например, mat) изнутри цикла. В любом случае, вы можете просто сделать foreach(mun = unique(dat$mun)).   -  person Roland    schedule 14.02.2018
comment
Кроме того, есть большая вероятность, что read.csv занимает большую часть времени. Если это так, рассмотрите возможность использования fread из пакета data.table (f означает fast). Это может быть на много порядков быстрее, и вам, возможно, не понадобится распараллеливание.   -  person Roland    schedule 14.02.2018
comment
В дополнение к предложению @Roland использовать fread, я не уверен, что это хороший кандидат на распараллеливание в любом случае, поскольку каждый цикл for требует чтения файла. Параллельное выполнение этих задач может очень легко привести к большему количеству обращений к диску и, таким образом, к замедлению, а не к ускорению работы.   -  person dww    schedule 14.02.2018
comment
хорошо. Спасибо вам за ваши предложения. Я буду читать больше вокруг него.   -  person 89_Simple    schedule 14.02.2018


Ответы (1)


Это может быть одним из решений. Обратите внимание, что здесь я использую окна и указал registerDoParallel(), чтобы он работал.

library(foreach)
library(doParallel)

# number of iterations
iters <- 5563

registerDoParallel()
mun <- unique(dat$mun)

tableList <- foreach(i=1:iters) %dopar% {
  dat <- read.csv(paste0("data",mun[i],".csv")
  tot.dat <- sum(dat$x)
}
unlist(tableList)

По сути, любой результат внутри {...} будет сохранен в списке. В этом случае результат (tot.dat, который является числом) компилируется в tableList, и, выполнив unlist(), мы можем преобразовать его в вектор для дальнейшего использования.

Результатом внутри {...} может быть что угодно, одно число, вектор, кадр данных или что угодно. Другим подходом к вашей проблеме было бы объединить все существующие данные вместе, пометив их соответствующим исходным файлом, поэтому средний компонент будет выглядеть примерно так:

library(plyr)
tableAll <- foreach(i=1:iters) %dopar% {
  dat <- read.csv(paste0("data",mun[i],".csv")
  dat$source = mun[i]
}
rbind.fill(tableAll)

Затем мы можем использовать его для дальнейшего анализа.

person Michael L. Tanny    schedule 14.02.2018