3

The following code:

df <- foreach(i = 1:length, .combine = cbind) %dopar% {
 ...
 ...
 m4
}

gives me an error :

error calling combine function:
<simpleError in data.frame(..., check.names = FALSE): arguments imply differing number of rows: 17, 0>

but, if I execute the same code with "for" instead of "foreach" and I also make the cbind manually:

for (i in 1:lengthGeni) {
...
...
mFinaleCGunificati <- cbind(mFinaleCGunificati, m4)
}

everthing works well

giupardeb
  • 791
  • 1
  • 5
  • 13
  • 1
    can you please come up with an appropriate [reproducible](https://stackoverflow.com/q/5963269/3250126) code? bc if I try to `cbind(as.data.frame(matrix(rep(1, 5), nrow = 5)), as.data.frame(matrix(rep(1, 0), nrow = 0)))` (which would correspond to what happens in your `for`loop approach) the same error is returned. – loki Oct 18 '17 at 09:01

1 Answers1

1

From ?cbind we learn that

If there are several matrix arguments, they must all have the same number of columns (or rows) and this will be the number of columns (or rows) of the result. If all the arguments are vectors, the number of columns (rows) in the result is equal to the length of the longest vector.

However if from the comparison of these two cbind examples

# second df with one row
cbind(as.data.frame(matrix(rep(1, 10), nrow = 5)), 
      as.data.frame(matrix(rep(2, 2), nrow = 1)))
#   V1 V2 V1 V2
# 1  1  1  2  2
# 2  1  1  2  2
# 3  1  1  2  2
# 4  1  1  2  2
# 5  1  1  2  2

# second df with zero rows
cbind(as.data.frame(matrix(rep(1, 10), nrow = 5)), 
      as.data.frame(matrix(rep(2, 0), nrow = 0)))
# Error in data.frame(..., check.names = FALSE) : 
#   arguments imply differing number of rows: 5, 0

we learn that zero-length objects are not allowed.

Therefore, you should check if your result in the loop has any number of rows greater than 0.

library(foreach)
library(doSNOW)
cl <- makeSOCKcluster(5)
registerDoSNOW(cl)

df <- foreach(i = 1:2, .combine = cbind) %dopar% {
  if (i == 1){
    x <- as.data.frame(matrix(rep(1, 5), nrow = 5))
  } else {
    x <- as.data.frame(matrix(rep(1, 2), nrow = 1))
  }

  # check if result has at least one row
  if (nrow(x) > 0){
    x
  }
}
df 
#   V1 V1 V2
# 1  1  2  2
# 2  1  2  2
# 3  1  2  2
# 4  1  2  2
# 5  1  2  2

However, keep in mind that shorter vectors will be reused. Thus this approach might lead to redundancies within the code.

To aviod redundancies, you might consider matching the lengths of the results before returning it in the foreach loop.

loki
  • 9,816
  • 7
  • 56
  • 82