用mclapply()替换多维数组上的嵌套for循环

时间:2020-10-14 14:48:17

标签: r for-loop lapply mclapply

我正在尝试对4维数组执行操作。这个数组最终变得非常大,但是对于我正在处理的数据来说是必需的。现在,过程本身开始膨胀,但是我想为并行计算做好准备。我可以使用96核大型机,我想使用它。

到目前为止,我已经在线阅读了最简单的方法是使用mclapply(),它是lapply()的并行版本。我知道lapply()的工作原理,但我不太想知道如何在这种情况下应用它。

我有一个充满NA的4维数组。每个维度都有一个昏暗的名字。我想比较维度1与维度3的暗名,以及维度2与维度4的暗名(这是由我编写的自定义函数完成的)。如果它们全部匹配,就会出现一个数字,我希望将该数字输入到xy [i,k,j,l]中,其中字母i-l代表一个条目的索引。

在下面的示例中,我将其简化为为暗名添加的nchar()值。

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()输出一个值列表。如何将其扩展到多个维度?

我已经看过这些帖子:

replace a nested for loop with mapply

replace nested foreach loops

但是这些方法中的每一个都以不利于我的方式解决了这个问题。

1 个答案:

答案 0 :(得分: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,因为expand.grid将data.frame的每一列(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]])