r - 使用 foreach 循环和并行处理生成矩阵

标签 r for-loop matrix foreach doparallel

我正在尝试转换一个 for 循环,我目前正在使用它来跨大型矩阵运行进程。当前的 for 循环查找 30 x 30 部分内的最大值,并使用最大值创建一个新矩阵。

for 循环的当前代码如下所示:

mat <- as.matrix(CHM) # CHM is the original raster image
maxm <- matrix(nrow=nrow(mat)/30, ncol=ncol(mat)/30) # create new matrix with new dimensions

for(i in 1:dim(maxm)[1]) {
  for(j in 1:dim(maxm)[2]) {
    row <- 30 * (i - 1) + 1
    col <- 30 * (j - 1) + 1
    maxm[i,j] <- max(CHM[row:(row + 29), col:(col + 29)])
   }
 }

我想将其转换为 foreach 循环以使用并行处理。我已经生成了以下代码,但这不起作用。我不确定如何在 foreach 循环中生成新矩阵:

ro<-nrow(mat)/30
co<-ncol(mat)/30
maxm <- matrix(nrow=nrow(mat)/30, ncol=ncol(mat)/30)

foreach(i=ro, .combine='cbind') %:%
  foreach(j=co, .combine='c') %dopar% {
    row <- 30 * (i - 1) + 1
    col <- 30 * (j - 1) + 1
    maxm[i,j]<-(max(CHM[row:(row + 29), col:(col + 29)]))
  }

请提出任何建议!

最佳答案

在并行执行任何操作之前,应尝试查看是否可以进行矢量化。一旦完成,问题“并行化合理吗?”

在这个特定的示例中,并行化不可能像您期望的那么快,因为在每次迭代时您都将输出保存到一个公共(public)对象中。 R 在并行化中通常不支持这一点,相反,人们应该在所谓的“令人尴尬的可并行”问题中寻求并行化,直到人们更好地理解并行问题的工作原理。简而言之:不要对 R 中的数据执行并行更改,除非您知道自己在做什么。它不太可能更快。

这就是说,就你的情况而言,它实际上变得相当棘手。您似乎正在执行“滚动最大窗口”,并且输出应该保存在组合矩阵中。将数据直接保存到矩阵中的另一种方法是返回一个包含 3 列 x、i、j 的矩阵,其中后者两个是指示 x 的值应放置在哪一行/哪列的索引。

为了使其发挥作用,正如 Dmitriy 在他的回答中指出的那样,需要将数据导出到每个集群(并行 session ),以便我们可以使用它。接下来的示例展示了如何执行并行化

首先:创建集群并导出数据集

set.seed(1)
#Generate test example
n <- 3000
dat <- matrix(runif(n^2), ncol = n)
library(foreach)
library(doParallel)
#Create cluster
cl <- parallel::makeCluster(parallel::detectCores())
#Register it for the foreach loop
doParallel::registerDoParallel(cl)
#Export the dataset (could be done directly in the foreach, but this is more explicit)
parallel::clusterExport(cl, "dat")

接下来我们进入foreach循环。请注意,根据文档,嵌套的 foreach 循环应使用 %:% 标记分隔,如下面的示例所示:

output <- foreach(i = 1:(nrow(dat)/30), .combine = rbind, .inorder = FALSE) %:% 
    foreach(j = 1:(ncol(dat)/30), .combine = rbind, .inorder = FALSE) %dopar%{
        row <- 30 * (i - 1) + 1
        col <- 30 * (j - 1) + 1
        c(x = max(dat[row:(row + 29), col:(col + 29)]), i = i, j = j)
    }

注意.inorder = FALSE。当我返回索引时,我不关心顺序,只关心速度。 最后但并非最不重要的一点是,我们需要创建矩阵。 Matrix 包函数 Matrix::SparseMatrix 允许指定值和索引。

output <- Matrix::sparseMatrix(output[,"i"], output[,"j"], x = output[,"x"])

这仍然相当慢。对于 n = 3000 ,执行计算大约需要 6 秒,而且导出数据的开销也不容忽视。但它可能比使用顺序循环的相同方法更快。

关于r - 使用 foreach 循环和并行处理生成矩阵,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56110411/

相关文章:

r - R 3.6 中的 mutate_at() 问题

r - 如何向 ggtree 的 `facet_plot` 中的构面添加图例?

c++ - 是否有理由跳过 for 循环的初始化?

c - C 中带有 char 迭代器的 FOR 循环是否可行?

algorithm - 将小数矩阵转换为整数矩阵

r - 无法删除列 - select() with dplyr

r - Win7 R 3.2.2 RStudio 0.99.473。安装 Hmisc 包时出错

JavaScript 简化 for 循环

java - 奇异矩阵和 Jama

arrays - Matlab:如何对二维数组进行排名并在另一个二维数组中标记排名?