首页 > 解决方案 > R并行计算与foreach通过不同的操作进行多个输出

问题描述

我想foreach用来提高计算速度。我想要做的是从单个 foreach 循环中输出两个结果。

以下是原始想法的简化版本:

output <- list(matrix_addition = matrix(0, nrow = 2, ncol = 2), process_list = list())

for(i in c(1:10)){
  # value_1 indicates some calculation to get the matrix
  value_1 <- i * 2

  # value_2 indicates some calculation to process_list for each i
  value_2 <- i / 2

  output$matrix_addition <- output$matrix_addition + matrix(value_1, nrow = 2, ncol = 2)
  output$process_list <- append(output$process_list, value_2)
}

预期output会像:

$matrix_addition
     [,1] [,2]
[1,]  110  110
[2,]  110  110

$process_list
$process_list[[1]]
[1] 0.5

$process_list[[2]]
[1] 1

...

$process_list[[10]]
[1] 5

我尝试将foreachwith.combine = "+"用于矩阵加法部分,但是当涉及到多个输出时,mapply似乎无法与"+". 我在网上找到了几个代码,使用.combine = "cbind", .multicombine=TRUE. 当涉及到两个输出的不同操作时,有什么办法吗?

谢谢您的帮助!

编辑:

foreach只添加矩阵的代码是

library(foreach)
library(doParallel)

cl <- makeCluster(2)
registerDoParallel(cl)

output <- foreach(i = 1:10, .combine = "+") %dopar% {
  value_1 <- i * 2
  matrix <- matrix(value_1, nrow = 2, ncol = 2)
}

stopCluster(cl)

我对这两个输出的第一次尝试是

output <- foreach(i = 1:10) %dopar% {
  if(exists("temp") == FALSE) {
    output <- list(matrix_addition = matrix(0, nrow = 2, ncol = 2), process_list = list())
  }

  value_1 <- i * 2
  value_2 <- i / 2

  output$matrix_addition <- output$matrix_addition + matrix(value_1, nrow = 2, ncol = 2)
  output$process_list <- append(output$process_list, value_2)
  output
}

原来for循环的思路好像不能直接用在foreach.

接下来,我在网上找到了这些代码,看起来是这样的:

comb <- function(...) {
  mapply("cbind", ..., SIMPLIFY=FALSE)
}

output <- foreach(i = 1:10, .combine="comb", .multicombine = TRUE) %dopar% {
  value_1 <- i * 2
  value_2 <- i / 2

  matrix_addition_part  <- matrix(value_1, nrow = 2, ncol = 2)
  process_list_part     <- value_2
  list(matrix_addition_part, process_list_part)
}

comb <- function(x, ...) {
  lapply(seq_along(x),
         function(i){c(x[[i]], lapply(list(...), function(y) y[[i]]))})
}

output <- foreach(i=1:10, .combine="comb", .multicombine=TRUE, .init=list(list(), list())) %dopar% {
  value_1 <- i * 2
  value_2 <- i / 2

  list(matrix(value_1, nrow = 2, ncol = 2), value_2)
}

这两个是类似的,这里的思路是把所有的矩阵都保存在矩阵相加部分,之后foreach,矩阵就可以相加了。但是对我来说问题是我的代码中的每个矩阵都太大了,需要很大的空间来存储,因此我无法保存所有矩阵。我想我需要将"cbind"矩阵加法部分替换为类似的东西"+",但它在mapply.

我的猜测是我需要使函数comp同时包含"+""append",但仍然无法通过利用apply.

标签: rforeachparallel-processing

解决方案


只需弄清楚如何做到这一点:

library(foreach)
library(doParallel)
cl <- makeCluster(2)
registerDoParallel(cl)

comb <- function(List1, List2) {
  output_a <- apply(abind(List1[[1]], List2[[1]], along = 3), 1:2, sum)
  output_b <- c(List1[[2]], List2[[2]])
  return(list(matrix_addition = output_a, process_list = output_b))
}

output <- foreach(i = 1:10, .combine = "comb", .init=list(matrix(0, 2, 2), list())) %dopar% {
  value_1 <- i * 2
  value_2 <- i / 2

  list(matrix_addition = matrix(value_1, nrow = 2, ncol = 2), process_list = value_2)
}

stopCluster(cl)

这里通过自定义.combine函数comb,将矩阵加法部分和进程列表部分分开,合并成一个列表。此外,函数的第一个输入(List1此处)comp将是.init或先前循环迭代(i-1)的结果,第二个输入(List2此处)将是当前循环迭代(i)的结果。


推荐阅读