FBM() из bigstatsr неправильно вычисляет матрицу при использовании параллельного foreach, как это происходит, когда код выполняется в простом цикле for.

Мне нужно оценить Матрицу перехода. Поскольку у меня много данных, я попытался запустить их параллельно, используя foreach, и я попробовал функцию общей памяти FBM() из bigstatsr. И похоже, что функция не всегда возвращает правильный результат. (Иногда да.) Может ли быть так, что функция не работает должным образом?

Вот пример, когда код работает правильно:

x <- c(1,2,1,1,3,4,4,1,2,4,1,4,3,4,4,4,3,1,3,2,3,3,3,4,2,2,3)
n <- length(unique(x))
A <- matrix(nrow = n, ncol = n, 0)
for (t in 1:(length(x) - 1)) {A[x[t], x[t + 1]] <- A[x[t], x[t + 1]] + 1}
A

А вот код, который не всегда возвращает правильный результат:

library(foreach)
library(doParallel)
library(bigstatsr)

cl <- makeCluster(8)
registerDoParallel(cl)

B <- FBM(n, n)
set.seed(3)

foreach (t = 1:(length(x) - 1))  %dopar% {B[x[t], x[t + 1]] <- B[x[t], x[t + 1]] + 1}
stopCluster(cl)

B[]
identical(A,B[])

То же самое происходит при использовании библиотеки snow

library(snow)
library(bigstatsr)
cl <- makeCluster(8)
f.trans.m <- function(t) {
  D[x[t], x[t + 1]] <<- D[x[t], x[t + 1]] + 1
}
D <- FBM(n, n)
clusterExport(cl, "f.trans.m")
clusterExport(cl, "D")
clusterExport(cl, "x")
parLapply(cl, seq(1,(length(x) - 1)), function(t) f.trans.m(t))
D[]
identical(A,D[])

Правильно ли я использую пакет, или в FBM() есть ошибка?

решение:

Отсутствовала блокировка файла, предоставляемая пакетом flock.

B <- FBM(n, n)
lock <- tempfile()
foreach (t = 1:(length(x) - 1))  %dopar% {
  locked <- flock::lock(lock)
  B[x[t], x[t + 1]] <- B[x[t], x[t + 1]] + 1
  flock::unlock(locked)
}

person 9001_db    schedule 07.02.2019    source источник
comment
Проблема здесь в том, что вы обновляете значения параллельно. Параллельное обновление значений — непростая задача. Взгляните на privefl.github .io/blog/a-guide-to-parallelism-in-r/.   -  person F. Privé    schedule 07.02.2019
comment
Флориан, спасибо за подсказку.   -  person 9001_db    schedule 07.02.2019


Ответы (1)


В этом конкретном примере проблема связана с параллельным одновременным обновлением значений (см. https://privefl.github.io/blog/a-guide-to-parallelism-in-r/#advanced-parallelism-synchronization).

Здесь я бы вообще не использовал параллелизм. Я бы предпочел последовательный (но векторизованный) метод доступа.

Я бы сначала перегруппировал индексы для увеличения:

library(dplyr)
ind <- data.frame(i = x[-length(x)], j = x[-1]) %>%
  group_by(i, j) %>%
  count()

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

B <- FBM(n, n, init = 0)
ind2 <- as.matrix(ind[1:2])
B[ind2] <- B[ind2] + ind[[3]]
person F. Privé    schedule 07.02.2019
comment
Флориан, большое спасибо за это решение. Действительно здорово! И спасибо за то, что вы так быстро ответили! - person 9001_db; 08.02.2019