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)
}

1 ответ

Решение

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

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

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

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]]
Другие вопросы по тегам