在并行编程中处理多维输出

问题描述:

我目前正在开发一个程序来评估模拟数据上几种预测模型的样本外性能。对于那些熟悉财务的人来说,它的工作原理与回溯交易策略一样,只是我会评估预测而非交易。在并行编程中处理多维输出

我目前使用for循环处理此类任务的一些对象是7维数组(尺寸代表蒙特卡罗复制,数据生成过程,预测层位,模型参数选择的3个维度和所有维度样本外分析所涵盖的时段)。很显然,它太痛苦了,所以并行计算已成为我的必需品。

我的问题是:如何跟踪R中超过2个维度?让我们只告诉你使用“for循环”,只有3个维度我的意思:

x <- array(dim=c(2,2,2)) 
    for (i in 1:2){ 
     for (j in 1:2){ 
     for (k in 1:2){ 
      x[i,j,k] <- i+j+k 
     } 
     } 
    } 

如果我使用类似“的foreach”,我对这样的事实很恼火的是,据我所知,可结合功能会返回列表,矩阵或向量 - 但不是任意大的多维数组。例如:

library(doParallel) 
library(foreach) 

# Get the number of cores to use 
no_cores <- max(1, detectCores()-1) 

# Make cluster object using no_cores 
cl <- makeCluster(no_cores) 

# Initialize cluster for parallel computing 
registerDoParallel(cl) 

x <- foreach(i=1:2, .combine=rbind)%:% 
     foreach(j=1:2, .combine=cbind)%:% 
     foreach(k=1:2, .combine=c)%dopar%{ 
      i+j+k 
    } 

在这里,我基本上将结果结合到向量中,然后矩阵和最后我按行堆积矩阵。另一个选择是使用列表,或者通过列堆积矩阵,但是当你有7个维度和数百万次的迭代跟踪时,你可以想象这个混乱。

我想我也可以编写自己的'combine'函数并获得我想要的输出类型,但是我怀疑我不是第一个遇到这个问题的人。要么有一种方法可以做到我想要的,或者有人可以指出一种对存储结果进行不同思考的方式。如果我正在采取一种荒谬而无效的方式来解决这个问题并不奇怪 - 毕竟我是经济学家,而不是数据科学家!

任何帮助将不胜感激。提前致谢。

我会做什么,我已经在我的一个包中使用bigstatsr。

只取一个尺寸并将它剪成no_cores块。它应该有足够的迭代次数(例如4个核心为20)。对于每次迭代,构建您想要的数组的一部分并将其存储在临时文件中。使用这些文件的内容来填充整个数组。通过这样做,你只填写预分配的对象,这应该更快,更容易。

例子:

x.all <- array(dim=c(20,2,2)) 
no_cores <- 3  
tmpfile <- tempfile()  
range.parts <- bigstatsr:::CutBySize(nrow(x.all), nb = no_cores) 

library(foreach) 
cl <- parallel::makeCluster(no_cores) 
doParallel::registerDoParallel(cl) 

foreach(ic = 1:no_cores) %dopar% { 

    ind <- bigstatsr:::seq2(range.parts[ic, ]) 
    x <- array(dim = c(length(ind), 2, 2)) 

    for (i in seq_along(ind)){ 
    for (j in 1:2){ 
     for (k in 1:2){ 
     x[i,j,k] <- ind[i]+j+k 
     } 
    } 
    } 

    saveRDS(x, file = paste0(tmpfile, "_", ic, ".rds")) 
} 
parallel::stopCluster(cl) 

for (ic in 1:no_cores) { 
    ind <- bigstatsr:::seq2(range.parts[ic, ]) 
    x.all[ind, , ] <- readRDS(paste0(tmpfile, "_", ic, ".rds")) 
} 

print(x.all) 

而不是写入文件,你也可以直接返回no_cores部分阵列的foreach和正确abind将它们结合起来。

+0

它实际上是一个非常好的解决方案。我花了一些时间和R一起工作,以“得到”你在这里做的事情,但是我会把这个建议放在后面,直到我有一些新的奇特工作要做。 –

有一个可用的解决方案,我终于在今晚偶然发现。我可以创建一个使用“abind”软件包中的“abind”功能沿着我所选择的尺寸合适的组合功能:

library(abind) 

# Get the number of cores to use 
no_cores <- max(1, detectCores()-1) 

# Make cluster object using no_cores 
cl <- makeCluster(no_cores) 

# Initialize cluster for parallel computing 
registerDoParallel(cl) 

mbind <- function(...) abind(..., along=3) 

x <- foreach(i=1:2, .combine=mbind)%:% 
    foreach(j=1:2, .combine=cbind)%:% 
    foreach(k=1:2, .combine=c)%dopar%{ 
     i+j+k 
} 

我还是想看看是否有人在做其他的意思我想但是。可能有很多方法可以做到这一点,我是R新手,但这种解决方案是一种明显的可能性。

+0

这是我使用的包和方法,但是你应该使用'multicombine = TRUE'选项以及'mbind',否则'mbind'永远不会被调用超过两个参数,这会显着伤害你的性能。有关类似问题的答案,请参阅https://*.com/a/17572065/2109128。 –