在 R 中将嵌套 for 循环转换为并行
Converting nested for-loop to parallel in R
您可以在下面找到 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 次模拟的平均值。
编辑:
嵌套的 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)
...之后。
原Post:
首先,您必须确定要用 foreach
循环替换 for
循环中的哪个。
基本上这个决定主要受循环结果的影响,因此,如何组合这些结果。由于您将单个进程外包给 PC 的各个处理器,因此只会返回最后一个元素。这些结果将按照 .combine
参数(例如 'c'
、'cbind'
等)中的说明进行组合。由于您正在尝试生成 two 列表,因此对于第一次启动来说这可能不是很容易。因此,我想举一个例子来概述嵌套在其他 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
你会注意到,这个循环的结果是一个列表。
您可以在下面找到 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 次模拟的平均值。
编辑:
嵌套的 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)
...之后。
原Post:
首先,您必须确定要用 foreach
循环替换 for
循环中的哪个。
基本上这个决定主要受循环结果的影响,因此,如何组合这些结果。由于您将单个进程外包给 PC 的各个处理器,因此只会返回最后一个元素。这些结果将按照 .combine
参数(例如 'c'
、'cbind'
等)中的说明进行组合。由于您正在尝试生成 two 列表,因此对于第一次启动来说这可能不是很容易。因此,我想举一个例子来概述嵌套在其他 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
你会注意到,这个循环的结果是一个列表。