我正在尝试转换一个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)]))
}
请提出任何建议!
答案 0 :(得分:2)
在并行执行任何操作之前,应尝试查看是否可以进行矢量化。一旦完成,问题“并行化是否合理?”
在此特定示例中,并行化不可能像您期望的那样快,因为在每次迭代中,您都将输出保存到一个公共对象中。 R通常不支持并行化,而是应该在所谓的“令人尴尬的可并行化”问题中寻求并行化,直到人们对并行问题的工作方式有了更好的了解。简而言之:除非您知道自己在做什么,否则不要对R中的数据执行并行更改。它不可能更快。
那对于您来说,这实际上变得非常棘手。您似乎正在执行“最大滚动窗口”,并且应将输出保存在组合矩阵中。直接将数据保存到矩阵中的另一种方法是返回具有3列x
,i
,j
的矩阵,其中后两个是指示哪个行/列的索引值x
应该放在其中。
如Dmitriy在他的回答中所指出的那样,为了使此工作有效,需要将数据导出到每个cluster
(并行会话),以便我们可以使用它。然后,以下示例显示了如何执行并行化
首先:创建一个集群并导出数据集
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秒钟来执行计算+导出数据的开销并不小。但这可能比使用顺序循环的相同方法要快。
答案 1 :(得分:0)
让我尝试在这里获得答案。
据我所知,R使用集群系统进行并行计算,每个节点都在自己的环境中工作。因此,对于foreach-%dopar%,首先,将所有当前的.globalEnv复制到每个群集节点,然后尝试运行在循环主体中编写的代码。代码执行后无回拷。您只会得到result = foreach(...) { }
的结果。因此,每个节点中的代码maxm[i,j]<-(max(CHM[row:(row + 29), col:(col + 29)]))
仅更改矩阵的本地副本,仅此而已。
因此,“正确”的代码可能会像这样:
mat <- as.matrix(CHM);
ro<-nrow(mat)/30;
co<-ncol(mat)/30;
maxm = foreach(i=1:ro, .combine='cbind') %:%
{
result = foreach(j = 1:co, .combine='c') %dopar%
{
row <- 30 * (i - 1) + 1;
col <- 30 * (j - 1) + 1;
max(CHM[row:(row + 29), col:(col + 29)]);
}
result;
}
也许还需要使用as.matrix
来达到最大值。