我正在尝试使用
foreach
和 doParallel
实现嵌套 for 循环,但我不想循环所有值的组合。基本上,我有一个方形数据集,我想对每对值运行一个函数,但我不需要重复 - 例如,我需要计算 [1,2] 的函数,而不是 [ 2,1],因为结果是相同的。这是一个非常基本的示例,但请注意,由于实际函数/计算的复杂性,我正在尝试使用 doParallel。
bvec <- seq(1,10,1)
avec <- seq(1,10,1)
x <- data.frame()
for (i in 1:10) {
for (j in i:10) {
x[i,j] <- sim(avec[i], bvec[j])
}
}
x
原始数据集约为 1800 x 1800,如果我进行所有成对计算,将导致超过 320 万次计算,这是不必要的。这是我为
foreach
准备的:
cl <- parallel::makeCluster(detectCores()-4)
doParallel::registerDoParallel(cl)
clusterExport(cl, list("bvec","avec"))
z <-
foreach(i=1:10, .combine="cbind") %:%
foreach(j=i:10) %dopar% {
x[i,j] <- sim(avec[i], bvec[j])
}
z
parallel::stopCluster(cl)
是否可以使用
foreach
来限制迭代?如果没有,还有其他方法可以优化这个过程吗?
我尝试将 foreach 语句更改为
foreach(i=1:10, .combine="cbind") %:%
foreach(j=i:10) %dopar% {
x[i,j] <- sim(avec[i], bvec[j])
}
但这显然行不通。
我在 1800x1800 数据上运行
microbenchmark
,并且您的嵌套 if()
三角形循环在 outer()
的计算次数上比 sum()
更快。
这是一种进行
foreach
嵌套的方法(从 https://cran.r-project.org/web/packages/foreach/vignettes/nested.html 的文档中提取)与 ifelse()
技巧相结合评估内循环并跳过半个三角形的重函数。
foreach(b=bvec, .combine='cbind') %:%
foreach(a=avec, .combine='c') %dopar% {
ifelse(a>=b, sum(a, b), NA)
}
这个想法 (
j=i:10
) 适用于 %do%
,但不适用于 %dopar%
,这在此线程中进行了讨论 https://stackoverflow.com/a/45920140/10276092 并表示“[%dopar%] 确实不改变全局对象[x]”
x <- matrix(NA, nrow = 10, ncol = 10)
foreach(i=1:10, .combine="cbind") %:%
foreach(j=i:10, .combine="c", .inorder=TRUE) %do% { # %do% works
x[i,j] <- sum(avec[i], bvec[j])
}
x
下面的方法可行,但是以一种奇怪的方式回收跳过的值。三角形形状不正确。来自 https://stackoverflow.com/a/48988950/10276092 的矩阵魔法使数据变得可呈现。
aa <- foreach(i=1:10, .combine="cbind") %:%
foreach(j=i:10, .combine="c", .inorder=TRUE) %dopar% {
sum(avec[i], bvec[j])
}
aa[col(aa) + row(aa) > nrow(aa) + 1] <- 0 # drop the recycling
aa
result.1 result.2 result.3 result.4 result.5 result.6 result.7 result.8 result.9 result.10
[1,] 2 4 6 8 10 12 14 16 18 20
[2,] 3 5 7 9 11 13 15 17 19 0
[3,] 4 6 8 10 12 14 16 18 0 0
[4,] 5 7 9 11 13 15 17 0 0 0
[5,] 6 8 10 12 14 16 0 0 0 0
[6,] 7 9 11 13 15 0 0 0 0 0
[7,] 8 10 12 14 0 0 0 0 0 0
[8,] 9 11 13 0 0 0 0 0 0 0
[9,] 10 12 0 0 0 0 0 0 0 0
[10,] 11 0 0 0 0 0 0 0 0 0