Как распараллелить алгоритм, который включает разреженную матрицу, в R

#r #parallel-processing #sparse-matrix

#r #параллельная обработка #разреженная матрица

Вопрос:

Я использую библиотеку ‘doParallel’ в R для увеличения скорости набора функций. Однако я столкнулся с ошибкой, которую не могу решить. Я считаю, что следующий код изолирует суть проблемы:

 library(Matrix)
library(doParallel)

test_mat = Matrix(c(0,1,2,NA,0,0,2,NA,1,NA,1,2,2,NA,0,1,0,2,2,2,0,0,NA,NA,1,2,1,1,2,1,rep(NA,5)), ncol=7, byrow=TRUE, sparse=TRUE)

par_func <- function(mat, ncores)
{
  cl <- makePSOCKcluster(ncores)
  clusterSetRNGStream(cl) 
  registerDoParallel(cl, cores = ncores)

  df = data.frame(1:7, NA)

  temp_vec = foreach(i=iter(df, by='row'), .combine=rbind) %dopar%
  {
    i[,2] <- sum(mat[,i[,1]] == 1, na.rm = TRUE)   1
  }
  stopCluster(cl)
  return(temp_vec)
}

par_func(mat=test_mat, ncores=5)
  

Который выдает следующее сообщение об ошибке:

 Error in { : task 1 failed - "object of type 'S4' is not subsettable" 
  

Эта функция работает, если ‘mat’ относится к классу ‘matrix’, а не ‘dgCMatrix’, поэтому проблема, по-видимому, связана с подмножеством разреженной матрицы. Есть ли у меня какие-либо варианты решения этой проблемы? Матрица ‘mat’ может быть очень большой и может содержать много нулей, поэтому я хотел бы продолжить работу с разреженными матрицами.

Ответ №1:

Основная проблема заключается в том, что рабочие не загрузили пакет Matrix, поэтому они не знают, как подмножество матричного объекта «mat». Вы можете исправить это с .packages помощью опции foreach:

 temp_vec = foreach(i=iter(df, by='row'), .packages='Matrix', .combine=rbind) %dopar% {
  # snip
}
  

Обратите внимание, что ваш пример не работает на всех платформах, но если бы вы зарегистрировали doParallel с:

 registerDoParallel(4)
  

тогда ваш цикл foreach работал бы в Linux и Mac OS X, но не работал в Windows! Причина в том, что в Linux и Mac OS X будет использоваться функция mclapply, но в Windows неявно создается объект кластера, а затем будет использоваться функция clusterApplyLB . Рабочие элементы разветвляются mclapply, поэтому они наследуют родительскую среду, включая загруженные пакеты, и, таким образом, цикл foreach работает. Но среда не наследуется рабочими при использовании makePSOCKcluster, поэтому вам нужно инициализировать среду рабочих, используя такие вещи, как .packages option , в противном случае цикл foreach завершается с ошибкой. Иронично, что, поскольку пакет doParallel скрывает это различие, чтобы упростить задачу, он создает небольшую ловушку переносимости для пользователей Windows.

Есть и другие способы улучшения этого примера (как упоминалось @agstudy), но, как я уже сказал, основная проблема заключается в том, что пакет Matrix не загружается на рабочих.

Комментарии:

1. Добавление команды .packages=Matrix работало для игрушечного кода в вопросе и для более сложной функции (не указанной в вопросе). Кроме того, спасибо за справочную информацию.

Ответ №2:

Вы не можете выполнить итерацию по объекту S4. iter Метод не определен для Matrix объекта.

  • Нет необходимости использовать df data.frame. Вам нужно просто перебирать столбцы
  • Приведение итератора к целому числу перед подмножеством.

Например, вы можете заменить свою функцию на 2 строки:

 foreach(i = seq_len(ncol(test_mat)), .combine=rbind) 
%dopar% sum(test_mat[,as.integer(i)]==1,na.rm=TRUE) 1

      [,1]
result.1    1
result.2    5
result.3    1
result.4    3
result.5    1
result.6    2
result.7    2