在R中将嵌套的for循环转换为并行
Posted
技术标签:
【中文标题】在R中将嵌套的for循环转换为并行【英文标题】:Converting nested for-loop to parallel in R 【发布时间】:2016-11-28 20:21:37 【问题描述】:您可以在下面找到 R 中的一段代码,我想将其转换为使用多个 CPU 作为并行进程运行。我尝试使用foreach
包,但没有走远.. 鉴于我有 3 级嵌套循环,我找不到一个很好的例子如何使它工作。帮助将不胜感激。下面的代码示例 - 我做了一个简单的函数,因此可以作为示例:
celnum <- c(10,20,30)
t2 <- c(1,2,3)
allrepeat <- 10
samplefunction <- function(celnum,t2)
x <- rnorm(100,celnum,t2)
y = sample(x, 1)
z = sample(x,1)
result = y+z
result
常规方式获取结果:
z_grid <- matrix(, nrow = length(celnum), ncol = length(t2))
repetitions <- matrix(, nrow = allrepeat, ncol = 1)
set.seed=20
for(i in 1:length(celnum))
for (j in 1:length(t2))
for (k in 1:allrepeat)
results <- samplefunction(celnum[i],t2[j])
repetitions[k] <- results
z_grid[i,j] <- mean(repetitions,na.rm=TRUE)
z_grid
现在尝试使用 foreach 做同样的事情:
set.seed=20
library(foreach)
library(doSNOW)
cl <- makeCluster(3, type = "SOCK")
registerDoSNOW(cl)
set.seed=20
output <- foreach(i=1:length(celnum),.combine='cbind' ) %:%
foreach (j=1:length(t2), .combine='c') %:%
foreach (k = 1:allrepeat) %do%
mean(samplefunction(celnum[i],t2[j]) )
output
这不像我希望的那样工作,因为它返回一个 30x2 维度的矩阵,而不是 3x3。我的意图是模拟 i 和 j 组合 k 次的场景,并希望获得 i 和 j 的每个组合的这些 k 模拟的平均值。
【问题讨论】:
或许你看看documentation @loki :谢谢,这很好。我可以用 foreach 运行一个简单的循环。然而,我确实很难转换这段代码,结果给我一个包含四个矩阵的列表的输出,并且有一个 3 级嵌套循环来运行该函数。我仍然在学习 R 【参考方案1】:编辑:
嵌套的 for 循环应该如下所示。请注意,只有一个 foreach
和两个 for
嵌套循环。
library(foreach)
library(doSNOW)
cl <- makeCluster(3, type = "SOCK")
registerDoSNOW(cl)
set.seed(20)
output <- foreach(k=1:allrepeat) %dopar%
df <- data.frame()
for (i in 1:length(t2))
for (j in 1:length(celnum))
df[i,j] <- mean(samplefunction(celnum[i],t2[j]))
df
结果output
也是list
。计算单元意味着this post 帮助很大。
library(plyr)
aaply(laply(output, as.matrix), c(2,3), mean)
# X2
# X1 V1 V2 V3
# 1 20.30548 21.38818 18.49324
# 2 40.09506 40.64564 40.34847
# 3 60.10946 59.68913 58.66209
顺便说一句:你应该...
stopCluster(cl)
... 之后。
原帖:
首先,您必须确定要用foreach
循环替换哪个for
循环。
基本上,这个决定主要受循环结果的影响,因此,如何组合这些结果。由于您将单个进程外包给 PC 的各个处理器,因此只会返回最后一个元素。这些结果将按照.combine
参数中的说明进行组合(例如'c'
、'cbind'
等)。由于您正在尝试生成 两个 列表,因此第一次开始这可能并不容易。因此,我想提出一个示例,概述嵌套在其他for
循环中的foreach
循环的功能。
library(foreach)
library(doSNOW)
dat1 <- c(15.2, 12.58, 4.25, 1.05, 6.78, 9.22, 11.20)
dat2 <- data.frame(matrix(1:15, ncol = 3))
cl <- makeCluster(3, type = "SOCK")
registerDoSNOW(cl)
for (i in 1:nrow(dat2))
FEresult <- foreach(j = 1:ncol(dat2), .combine = c, .inorder = TRUE) %dopar%
tmp <- dat1 * dat2[i, j]
data.frame(tmp)
FEresult
if (i == 1)
res <- FEresult
else
res <- rbind(res, FEresult)
res
你会注意到,这个循环的结果是一个列表。
【讨论】:
谢谢。我决定稍微简化一下这个功能(见编辑过的帖子)。你介意看看,看看最终的调整会帮助它工作吗? 当我复制循环时,它可以工作。也许您将错误消息编辑到您的问题中,以便我可以查看它 没有错误信息,但结果不如预期。我想在output
中获得与z_grid
相同的结果。前者是 [i,j] 的 [3,3] 矩阵,其中该矩阵的 k 次模拟被总结为每个矩阵条目的平均值。这有意义吗?换句话说,我对 i 和 j 组合的场景进行了 k 次模拟,并希望得到 i 和 j 的每个组合的这 k 个模拟的平均值。 foreach
的当前输出给了我 30x3 的输出尺寸,我什至不确定它们是如何排序的。
谢谢,这个例子很好用。但是,当我用我更复杂的功能(完全工作,安装所有库,与我以前的循环等)替换此功能时,使用 %dopar% 我收到一条错误消息:Error in : task 1 failed - "could not find function "SpatialPoints""
。当我做 %do% 没有问题并且语句被执行。遇到过这样的问题吗?
您必须添加参数 foreach (..blabla.., .packages = c("sp", "rgdal")
或您想在 foreach 循环期间使用的任何包。因此,包是在各个进程中加载的。以上是关于在R中将嵌套的for循环转换为并行的主要内容,如果未能解决你的问题,请参考以下文章