Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

outptut two objects using foreach

I would like to know if it would be possible to output two different objects after using foreach %dopar% loop.

I will try to explain what I am looking for. Let's suppose I have two data.frames as a result of several operations inside the loop:

library(doMC)
library(parallel)
registerDoMC(cores=4)

result <- foreach(i=1:100) %dopar% {
#### some code here
#### some code here
vec1 <- result_from_previous code # It would be the 1st object I'd like to ouput
vec2 <- result_from_previous code # It would be the 2nd object I'd like to output
}

My desired output would be a list of data.frames of length 2, such as:

dim(result[[1]]) # equals to nrow=length(vec1) and ncol=100
dim(result[[2]]) # equals to nrow=length(vec2) and ncol=100

I have tried with this from a previous post Saving multiple outputs of foreach dopar loop:

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

result <- foreach(i=1:100, .comb='comb', .multicombine=TRUE) %dopar% {
#### some code here
#### some code here
vec1 <- result_from_previous code 
vec2 <- result_from_previous code 
list(vec1, vec2)
}

But it doesn't give the expected result

When I do the following:

result <- foreach(i=1:100, .comb=cbind) %dopar% {
#### some code here
#### some code here
vec1 <- result_from_previous code 
vec2 <- result_from_previous code 
}

I obtain only the data.frame of vec2. Is there any way of returning or saving both outputs?

Thanks

like image 847
user2380782 Avatar asked Feb 05 '15 16:02

user2380782


1 Answers

If you need to return two objects from the body of the foreach loop, you must bundle them into one object somehow or other, and a list is the most general way to do that. The trick is to provide an appropriate combine function to achieve the desired final result. If you want to combine all of the vec1 objects with cbind, and also all of the vec2 objects with cbind, the mapply function is quite handy. I think this is what you want:

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

Here's a little test program for this combine function:

result <- foreach(i=1:100, .combine='comb', .multicombine=TRUE) %dopar% {
  vec1 <- rep(i, 10)
  vec2 <- rep(2*i, 10)
  list(vec1, vec2)
}

This will return a list containing two, 10 X 100 matrices, but the same combine function can be used if vec1 and vec2 are data frames.

like image 108
Steve Weston Avatar answered Nov 07 '22 03:11

Steve Weston