R foreach() - 使用 itertools 块时如何为多个输出定义组合函数?



如何为使用 itertools 分块的 R foreach(( 语句编写组合函数,以便获得与使用 R foreach(( 语句而不进行 itertools 分块相同的结果?

我有一个 R foreach(( 语句,它执行计算并返回三个列表的列表。 在下面的第一个代码块中,给出了所需输出的简化版本 - 它使用我在保存每个 dopar 循环的多个输出中找到的组合函数。

现在我想使用迭代工具中的分块来运行相同的代码。 我尝试了两种不同的方法(请参阅下面的第二个和第三个代码块(,但没有产生预期的结果。 问题在于,在我两次尝试合并 itertools 分块时,three_lists不是由 3 个列表的 10 个列表组成,three_lists 是由 3 个列表组成的,每个列表都有 2 个列表(在不同的尝试中,2 个不同长度的列表(。 我猜测列表的长度为 2 而不是 10,因为我计算机上num_cores是 2 - 这对我来说表明,在使用 itertools 分块时,我的组合函数可能需要更改以正确组合输出。 不过,我无法弄清楚如何更改它。 我应该如何更改组合功能?

下面是生成所需结果的 foreach(( 语句:

# set up
library(foreach)
library(doParallel)
# set parallel options
num_cores_total <- detectCores() 
num_cores <- num_cores_total - 2
cl <- makeCluster(spec= num_cores, type="PSOCK")
registerDoParallel(cl, cores = num_cores)
# create function that will separate out foreach output into list of three lists
comb <- function(x, ...) {
lapply(seq_along(x),
function(i) c(x[[i]], lapply(list(...), function(y) y[[i]])))
}
# foreach statement
three_lists <- foreach(i = 1:10, .inorder=TRUE, .combine='comb', .multicombine=TRUE, .init=list(list(), list(), list())) %dopar% {
first_output <- i*1
second_output <- i*10
third_output <- i*100
list(first_output, second_output, third_output)
}
first_output_list <- three_lists[[1]]
second_output_list <- three_lists[[2]]
third_output_list <- three_lists[[3]]

这是我第一次(不成功(尝试将迭代工具分块合并到代码中:

# set up
library(foreach)
library(itertools)
library(doParallel)
# set parallel options
num_cores_total <- detectCores() 
num_cores <- num_cores_total - 2
cl <- makeCluster(spec= num_cores, type="PSOCK")
registerDoParallel(cl, cores = num_cores)
# create function that will separate out foreach output into list of three lists
comb <- function(x, ...) {
lapply(seq_along(x),
function(i) c(x[[i]], lapply(list(...), function(y) y[[i]])))
}
# foreach statement
three_lists <- foreach(thisIter=isplitIndices(10, chunks=num_cores), .inorder=TRUE, .combine='comb', .multicombine=TRUE, .init=list(list(), list(), list())) %dopar% {
first_output <- thisIter*1
second_output <- thisIter*10
third_output <- thisIter*100
list(first_output, second_output, third_output)
}
first_output_list <- three_lists[[1]]
second_output_list <- three_lists[[2]]
third_output_list <- three_lists[[3]]

# stop cluster
stopCluster(cl)

这是我第二次(不成功(尝试将迭代工具分块合并到代码中:

# set up
library(foreach)
library(itertools)
library(doParallel)
# set parallel options
num_cores_total <- detectCores() 
num_cores <- num_cores_total - 2
cl <- makeCluster(spec= num_cores, type="PSOCK")
registerDoParallel(cl, cores = num_cores)
# create function that will separate out foreach output into list of three lists
comb <- function(x, ...) {
lapply(seq_along(x),
function(i) c(x[[i]], lapply(list(...), function(y) y[[i]])))
}
# foreach statement
three_lists <- foreach(thisIter=isplitIndices(10, chunks=num_cores), .inorder=TRUE, .combine='comb', .multicombine=TRUE, .init=list(list(), list(), list())) %dopar% {
calc_function <- function(x){
first_output <- x*1
second_output <- x*10
third_output <- x*100
return(list(first_output, second_output, third_output))
}
sapply(thisIter, calc_function)  
}
first_output_list <- three_lists[[1]]
second_output_list <- three_lists[[2]]
third_output_list <- three_lists[[3]]
# stop cluster
stopCluster(cl)

这个想法是您可以使用.combine=c来附加以块形式返回的列表 (这样你就不会得到嵌套列表(, 然后按照您没有itertools的方式调整结构 (但简化了一点(:

lists <- foreach(thisIter=isplitIndices(10L, chunks=num_cores), .combine=c) %dopar% {
lapply(thisIter, function(i) {
c(i * 1L, 
i * 10L,
i * 100L)
})
}
first_output_list <- lapply(lists, "[", 1L)
second_output_list <- lapply(lists, "[", 2L)
third_output_list <- lapply(lists, "[", 3L)

最新更新