Использование цикла foreach в r возвращает NA

Я хотел бы использовать цикл foreach в R (пакет foreach + doParallel), но в своей работе я обнаружил, что цикл возвращает некоторый NA, а классический цикл for возвращает значение, которое я хочу:

    library(foreach)
    library(doParallel)

    ncore=as.numeric(Sys.getenv('NUMBER_OF_PROCESSORS'))-1
    registerDoParallel(cores=ncore)

    B=2

    a = vector()
    b = vector()

    foreach(i = 1:B, .packages = "ez",.multicombine = T,.inorder = T, .combine = 'c')%dopar%{
      a[i] = i + 1
      return(a)
    }

    for(i in 1:B){
      b[i] = i + 1
      b
      }

Как вы можете видеть, если вы попробуете, объект "a" возвращает вектор с 2, NA и 3, а объект "b" возвращает 2 и 3 (это то, что я хочу).

Я на самом деле не могу понять, почему в моих результатах есть "NA"...


person Rhevan    schedule 28.08.2017    source источник
comment
Повтор цикла foreach выполняется для i = 1, a = c(2), но для i = 2 это a = c(NA, 3), потому что вектор инициализируется перед циклом и пуст для каждого отдельного цикла. Внутри цикла for, когда он вызывается во второй раз, он уже не пуст. Поэтому в .combine оно добавляется к c(2, NA, 3).   -  person Jakob Gepp    schedule 28.08.2017
comment
Спасибо за Ваш быстрый ответ! Помогли понять как это работает!   -  person Rhevan    schedule 28.08.2017


Ответы (2)


Это связано с тем, что foreach не изменяет глобальный объект a. Попробуйте совместить с list. Будет легче понять, что происходит. Я увеличил B до 3.

> B=3
> 
> a = vector()
> 
> foreach(i = 1:B, .multicombine = T, .inorder = T, .combine = 'list') %dopar% {
+   a[i] = i + 1
+   return(a)
+ }
[[1]]
[1] 2

[[2]]
[1] NA  3

[[3]]
[1] NA NA  4

Мы видим, что на каждой итерации берется пустой вектор a и заполняется одно его значение. Если вы c объедините результат, вы получите NA значений.

> foreach(i = 1:B, .multicombine = T, .inorder = T, .combine = 'c') %dopar% {
+   a[i] = i + 1
+   return(a)
+ }
[1]  2 NA  3 NA NA  4

В этом примере вы могли бы сделать.

> a <- foreach(i = 1:B, .multicombine = T, .inorder = T, .combine = 'c') %dopar% {
+   i + 1
+ }
> a
[1] 2 3 4
person djhurio    schedule 28.08.2017
comment
Спасибо большое! Теперь я лучше понимаю, как работает цикл foreach, и я буду использовать его в своей более сложной работе (это было просто для того, чтобы попытаться понять, что происходит). - person Rhevan; 28.08.2017

foreach работает больше как lapply, чем цикл for.

Вы можете просто сделать foreach(i = 1:B, .combine = 'c') %dopar% { i + 1 } (.multicombine и .inorder уже являются TRUE, но вы можете установить .maxcombine на высокое значение).

person F. Privé    schedule 28.08.2017