Далее с пакетом foreach Revolution R? - PullRequest
16 голосов
/ 10 октября 2011

Я просмотрел большую часть документации и провел немало поисков в Google, но не могу найти ответ на следующий вопрос: есть ли способ вызвать «похожую» функциональность в параллели foreachцикл с использованием пакета foreach?

В частности, я хотел бы сделать что-то вроде (это не работает с next, но без):

foreach(i = 1:10, .combine = "c") %dopar% {
    n <- i + floor(runif(1, 0, 9))
    if (n %% 3) {next}
    n
}

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

Есть ли здесь простой обходной путь (функциональность следующего типа или другой способподходить к проблеме)?

Ответы [ 2 ]

12 голосов
/ 10 октября 2011

Вы можете поместить свой код в функцию и вызвать return. Из вашего примера не ясно, что вы хотите, чтобы он делал, когда n %% 3, поэтому я вернусь NA.

funi <- function(i) {
  n <- i + floor(runif(1, 0, 9))
  if (n %% 3) return(NA)
  n
}
foreach(i = 1:10, .combine = "c") %dopar% { funi(i) }
9 голосов
/ 12 марта 2013

Хотя это кажется странным, вы можете использовать return в теле цикла foreach, без необходимости во вспомогательной функции (как продемонстрировал @Aaron):

r <- foreach(i = 1:10, .combine='c') %dopar% {
  n <- i + floor(runif(1, 0, 9))
  if (n %% 3) return(NULL)
  n
}

A NULL возвращается в этом примере, поскольку оно отфильтровывается функцией c, что может быть полезно.

Кроме того, хотя для вашего примера это не очень хорошо работает, функция when может иногда заменять next и полезна для предотвращения вычислений вообще:

r <- foreach(i=1:5, .combine='c') %:%
         foreach(j=1:5, .combine='c') %:%
             when (i != j) %dopar% {
                 10 * i + j
             }

Внутреннее выражение вычисляется только 20 раз, а не 25. Это особенно полезно для вложенных циклов foreach, поскольку when имеет доступ ко всем значениям итератора в восходящем направлении.


Обновление

Если вы хотите отфильтровать NULL s при возврате результатов в списке, вам нужно написать собственную функцию объединения. Вот полный пример, который демонстрирует функцию объединения, которая работает как функция объединения по умолчанию, но включает в себя механизм фильтрации:

library(doSNOW)
cl <- makeSOCKcluster(3)
registerDoSNOW(cl)

filteredlist <- function(a, ...) {
  values <- list(...)
  c(a, values[! sapply(values, is.null)])
}

r <- foreach(i=1:200, .combine='filteredlist', .init=list(),
             .multicombine=TRUE) %dopar% {
  # filter out odd values of i
  if (i %% 2) return(NULL)
  i
}

Обратите внимание, что этот код работает правильно, когда имеется более 100 результатов задачи (100 - значение по умолчанию для опции .maxcombine).

...