тройной цикл с использованием R foreach

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

library(foreach)
library(doParallel)

aa <-  seq(1,10, length=4)
bb <- seq(0,1, length=4)
cc <- seq(0,1, length=4)

fun <- function(a,b,c){return(a+b-c)}
out <- array(NaN, dim=c(4,4,4))

registerDoParallel()
out <- foreach(i = aa, .combine='cbind', .multicombine=TRUE) %dopar% {
  foreach(j = bb, .combine='cbind', .multicombine=TRUE) %:%
    foreach(k = cc, .combine='c') %dopar% { fun(i, j,k) }
}

person T_D    schedule 10.10.2013    source источник


Ответы (2)


Проблема в том, что cbind объединяет матрицы по столбцам в большую матрицу. Что вам нужно, так это функция, которая объединяет матрицы в трехмерные массивы, например, функция abind из пакета abind. Поскольку ей нужен дополнительный аргумент, я определяю функцию объединения как:

mbind <- function(...) abind(..., along=3)

Вот как я бы использовал это для вашего примера:

library(abind)
library(doParallel)
registerDoParallel()
aa <- seq(1,10, length=4)
bb <- seq(0,1, length=4)
cc <- seq(0,1, length=4)

fun <- function(a,b,c) {return(a+b-c)}
mbind <- function(...) abind(..., along=3)

out <-
  foreach(i=aa, .combine='mbind', .multicombine=TRUE) %:%
    foreach(j=bb, .combine='cbind') %:%
      foreach(k=cc, .combine='c') %dopar% {
        fun(i, j, k)
      }

В Linux и Mac OS X весь этот вложенный цикл будет преобразован в один вызов mclapply. Если объединение результатов занимает слишком много времени, может быть лучше распараллелить только внешний цикл, как это предлагает mrip, чтобы рабочие выполняли большую часть объединения.

person Steve Weston    schedule 10.10.2013
comment
Расширение вашего ответа до четырехкратного цикла не так очевидно, или, возможно, я просто медлю. Если вы/кто-то еще может помочь снова, я буду благодарен - person T_D; 09.05.2014

У вас есть все нужные данные, вам просто нужно изменить размеры:

dim(out)<-c(4,4,4)

Если вы хотите, чтобы размеры были такими, что out[i,j,k] == fun(aa[i],bb[k],cc[k]), вам нужно переставить их так:

out<-aperm(out,c(3,2,1))

Это можно проверить:

out2<-array(0,dim(out))
for(i in 1:4)
  for(j in 1:4)
    for(k in 1:4)
      out2[i,j,k]<-fun(aa[i],bb[j],cc[k])

identical(out,out2)
## [1] TRUE
person mrip    schedule 10.10.2013
comment
Спасибо, это помогает! Любые советы по функции foreach также будут отличными! В любом случае, ваш ответ полезен! - person T_D; 10.10.2013
comment
Вам, вероятно, не нужен %dopar% в третьем цикле. Попробуйте вместо этого использовать %do%, это может быть быстрее. Обычно лучше распараллелить как можно грубее, чтобы тратить меньше времени на разделение задач между потоками и больше времени на выполнение работы. - person mrip; 10.10.2013