0

I have seen a couple related questions on this topic, for instance here and here but the solutions don't seem to work for me as far as I can tell.

I have a function that returns a 5x3 matrix. I use mapply to iterate the function 4 times. My goal is to have the mapply call return a 20x3 matrix, but instead it returns a 15x4 matrix.

population <- runif(100, 0, 1)
iterations <- seq(1:4)

test.func <- function(k){
    samp1 <- sample(population, 20, replace = FALSE)
    samp2 <- sample(population, 20, replace = FALSE)
    samp3 <- sample(population, 20, replace = FALSE)

    ## Pre-allocate 
    c1 <- NULL
    c2 <- NULL
    c3 <- NULL

    for (i in 1:5){
       c1[i] <- samp1[i]
       c2[i] <- samp2[i]
       c3[i] <- samp3[i]
    }

combined <- cbind(c1, c2, c3)
print(combined)
}

results <- mapply(FUN = test.func, k = iterations)

I tried a transpose within the function, but that didn't help. I'd be open to options that fix the problem after calling mapply too.

One alternative would be to convert the 5x3 matrices to data frames and then separate them into a 3x20 matrix and transpose it. But I am hoping there is a more sensible way.

Community
  • 1
  • 1
Amberopolis
  • 445
  • 1
  • 6
  • 16
  • 1
    `mapply` is a multivariate version of `sapply`, which simplifies its result using `simplify2array` (unless you tell it otherwise). You don't need `mapply` since you only have one variable being passed. You can use `do.call(rbind, lapply(iterations, test.func))` You're also never passing `k` into the function, so you could even use `replicate` – Rich Scriven Nov 27 '14 at 19:28
  • @Richard, good catch. My actual application uses a parallel version of mapply (mcmapply). If there is a parallel version of sapply or--especially--replicate, I'd love to know. My impression is that this doesn't exist, but I could easily be wrong. – Amberopolis Nov 27 '14 at 19:36
  • @Richard - nonetheless, I can just use your do.call option with mclapply and that should work (I'll have to test it in my actual application, but it works on the test data). If you submit your comment as an answer, I'll accept it. Thanks! – Amberopolis Nov 27 '14 at 19:57

1 Answers1

2

mapply is a multivariate version of sapply, which simplifies its result using simplify2array (unless you tell it otherwise). You don't need to use mapply since you only have one variable being passed to your function (actually, you have no variables being passed - see below). In base R, you can use

do.call(rbind, lapply(iterations, test.func)) 

Other options that can replace do.call(rbind, ...) are data.table::rbindlist and plyr::rbind.fill

Also, you're never passing k into the function, so you could even use replicate. But again, since replicate is essentially sapply you'd need simplify = FALSE

test.func()  ## notice that k is not used at all
#             c1         c2         c3
# [1,] 0.6087179 0.04439165 0.11227567
# [2,] 0.8915234 0.79688365 0.02446302
# [3,] 0.5635389 0.17794940 0.16731767
# [4,] 0.7040224 0.17201792 0.28175588
# [5,] 0.8999534 0.28175588 0.58302149

PS - I also condensed your last two lines in to one

combined <- cbind(c1, c2, c3)
print(combined)

can just be

cbind(c1, c2, c3)

That print call can make things frustrating when you assign x <- test.func()

Rich Scriven
  • 97,041
  • 11
  • 181
  • 245