在R中的三维数组上并行化嵌套for循环

时间:2016-07-22 07:58:19

标签: arrays r multidimensional-array foreach parallel-processing

在Windows机器上使用R,我目前在3D阵列(720x360x1368)上运行嵌套循环,循环通过d1和d2以在d3上应用函数并将输出组合到具有类似维度的新数组。

在下面的可重复示例中,我将维度减少了10倍,以使执行更快。

library(SPEI)

old.array = array(abs(rnorm(50)), dim=c(72,36,136))

new.array = array(dim=c(72,36,136))

for (i in 1:72) {
  for (j in 1:36) {
    new.listoflists <- spi(ts(old.array[i,j,], freq=12, start=c(1901,1)), 1, na.rm = T)
    new.array[i,j,] = new.listoflists$fitted
  }
}

其中spi()是SPEI包中的函数,返回列表列表,其中每个循环增量使用一个长度为1368的特定列表$fitted来构造新数组。

虽然这个循环完美无缺,但计算需要相当长的时间。我已经读过foreach可用于并行化for循环。

但是,我不明白如何实现新阵列的嵌套和组装,以使旧阵列和新阵列的dimnames保持一致。

(最后,我希望能够使用as.data.frame.table()将旧数组和新数组转换为“平面”长面板数据框,并将它们合并在一起尺寸。)

有关如何使用并行计算实现所需输出的任何帮助都将受到高度赞赏!

干杯
CubicTom

2 个答案:

答案 0 :(得分:0)

通过可重复的示例本来会更好,这是我想出的:

首先创建要使用的群集

cl <- makeCluster(6, type = "SOCK")
registerDoSNOW(cl)

然后创建循环并关闭集群:

zz <- foreach(i = 1:720, .combine = c) %:% 
foreach(j = 1:360, .combine = c ) %dopar% {
new.listoflists <- FUN(old.array[i,j,])
new.array[i,j,] <- new.listoflists$list
}
stopCluster(cl)

这将创建一个列表zz,其中包含new.array [i,j,]的每次迭代,然后您可以将它们绑定在一起:

new.obj <- plyr::ldply(zz, data.frame)

希望这能帮到你!

答案 1 :(得分:0)

我没有使用与你的问题一样多的维度,因为我想确保行为是正确的。 所以在这里我使用带有多个参数的mapply。结果是结果列表。然后我用matrix()包装它以获得你希望的尺寸。 请注意,使用重复 i ,并使用每次重复 j 。这是至关重要的,因为matrix()先按行放入条目,然后在达到行数时换行到下一列。

new.array = array(1:(5*10*4), dim=c(5,10,4))

# FUN: function which returns lists of 
FUN <- function(x){
    list(lapply(x, rep, times=3))
}

# result of the computation
result <- matrix(
    mapply(
        function(i,j,...){

            FUN(new.array[i,j,])
        }
        ,i = rep(1:nrow(new.array),times=ncol(new.array))
        ,j = rep(1:ncol(new.array),each=nrow(new.array))
        ,new.array=new.array
    )
    ,nrow=nrow(new.array)
    ,ncol=ncol(new.array)
)