заменить вложенные циклы for в многомерном массиве на mclapply()

Я пытаюсь выполнить действие над четырехмерным массивом. Этот массив оказывается невероятно большим, но он необходим для данных, которые я обрабатываю. Теперь сам процесс идет хорошо, но я хочу подготовить его к параллельным вычислениям. У меня есть доступ к 96-ядерному мейнфрейму, и я хочу его использовать.

До сих пор я читал в Интернете, что самый простой способ сделать это — использовать mclapply(), распараллеленную версию lapply(). Я знаю основы работы lapply(), но не могу понять, как это применить в данной ситуации.

У меня есть 4-мерный массив, заполненный NA. Каждое измерение имеет dimnames. Я хочу сравнить dimnames измерения 1 с измерением 3 и измерения 2 с измерением 4 (это делается с помощью пользовательской функции, которую я написал). Если все они совпадают, выходит число, и я хочу, чтобы это число было введено в xy[i, k, j, l], где буквы i-l представляют индексы для одной записи.

В приведенном ниже примере я упростил его до добавления значений nchar() для dimnames.

xy <- array(NA, dim = c(10, 10, 10, 10), dimnames = list(c("john", "sandra", "peter", "linda", "max", "sam", "ana", "enzo", "juan", "abe"), 
                                                          c("smith", "gonzalez", "doe", "dopi", "lincoln", "biden", "rutte", "merkel", "slim", "shady"),
                                                          c("jon", "sam", "pete", "melinda", "max", "sam", "anna", "carlo", "jiro", "abel"),
                                                          c("smitty", "rupinder", "dole", "mite", "lincolan", "bidet", "rourke", "meer", "smart", "sunny")))

for(i in 1:dim(xy)[1]){
    for(j in 1:dim(xy)[3]){
      for(k in 1:dim(xy)[2]){
        for(l in 1:dim(xy)[4]){
          a <- nchar(dimnames(xy)[[1]][i]) + nchar(dimnames(xy)[[3]][j])
          b <- nchar(dimnames(xy)[[2]][k]) + nchar(dimnames(xy)[[4]][l])
          if(!is.null(a) & !is.null(b)){
            xy[i, k, j, l] <- a + b
          }
        }
      }
    }
  }

моя проблема в том, что мой вывод должен быть многомерным массивом. до сих пор я использовал только lapply() для вывода одного списка значений. Как мне расширить это на несколько измерений?

Я уже смотрел в этих постах:

заменить вложенный цикл for на mapply

заменить вложенные циклы foreach

но каждый из них решает вопрос таким образом, который не помогает моему.


person JadaLovelace    schedule 14.10.2020    source источник


Ответы (1)


fun_on_names <- function(Var1, Var2, Var3, Var4){
 
 a <- nchar(Var1) + nchar(Var3)
 b <- nchar(Var2) + nchar(Var4)
 
 if(!is.null(a) & !is.null(b)) return(a + b)
 else return(NA)
 
}

xy[] <- do.call(parallel::mcmapply, 
                c(list(FUN = fun_on_names, mc.cores = 96),
                  expand.grid(dimnames(xy), stringsAsFactors = FALSE)))

Идея такова:

  • создайте с помощью expand.grid большой data.frame всех комбинаций имен, которые у вас есть.
  • применить функцию fun_on_names к каждой комбинации
  • применить результат обратно к xy

На самом деле функция возвращает числовой вектор, но, сохраняя [] в xy[]<-, вы присваиваете значения обратно xy, сохраняя нетронутыми атрибуты xy, что делает его многомерным массивом.

Это решение не работает параллельно в Windows.

do.call не требуется, чтобы каждый столбец data.frame (выход expand.grid) обрабатывался mcapply как отдельные векторы.

Вы можете увидеть это как:

df <- expand.grid(dimnames(xy), stringsAsFactors = FALSE)
xy[] <- parallel::mcmapply(FUN = fun_on_names, 
                           mc.cores = 96,
                           df[[1]], df[[2]], df[[3]], df[[4]])
person Edo    schedule 14.10.2020