R: Using mapply with additional lists as arguments
Asked Answered
C

2

5

I have the following list and vectors of parameters:

myList <- list(c(3, 0, 1), c(2, 2, 2))
vPar1 <- c(1, 5, 100)
vPar2 <- c(100, 5, 1)

and I'm trying to draw samples from 3 Beta distributions with shape parameters shape1 = vPar1 and shape2 = vPar2 (element-wise).

The expected result would be a list with two elements: the first element would consist of 4 random numbers (3 from a Beta(1, 100) and 1 from a Beta(100, 1) distribution) whereas the second list element would consist of a total of 6 random numbers (2 random numbers of a Beta(1, 100), Beta(5, 5) and Beta(100, 1) distributions each).

I tried to produce the required result using mapply i.e. cycling through the elements of the 3 arguments, but I can't figure how it should be used exactly:

mapply(function(x, shape1, shape2) {unlist(rbeta(x, shape1, shape2))}, 
          myList, 
          MoreArgs = list(shape1 = vPar1, shape2 = vPar2), 
          SIMPLIFY = FALSE)

This results in a list of two elements but with 3 random numbers each, insetad of the expected 4 and 6 numbers respectively. I'd be grateful for any suggestions! Thanks.

Cocaine answered 25/11, 2019 at 21:12 Comment(1)
From the help: n number of observations. If length(n) > 1, the length is taken to be the number required. So the actual values in your myList vectors are being ignored. Their length , 3, is being usedPigpen
G
5

One option is to loop over the list with lapply and then apply the 'vPar1' and 'vPar2' as arguments in a nested Map within the lapply

lapply(myList, function(x) unlist(Map(rbeta, n = x, shape1 = vPar1, shape2 = vPar2)))
#[[1]]
#[1] 0.031955823 0.001533638 0.012877288 0.998004973

#[[2]]
#[1] 0.021860350 0.002145949 0.514477229 0.479578366 0.996876238 0.992356962

It can also be written as

lapply(Map(Vectorize(rbeta), myList, MoreArgs = list(shape1 = vPar1, 
        shape2 = vPar2)), unlist)
Geesey answered 25/11, 2019 at 21:21 Comment(1)
That is absolutely brilliant! You will not believe how long I spent (in vain) trying to figure it out. Thanks!Cocaine
A
1

Out of curiosity, I wanted to see if you could do this without nested lapply/Map. I don't think there's any benefit to doing it this way, but here it is. Use Vectorize so you don't have to use Map inside lapply (well, don't have to type it out at least), then use compose so you don't have to do another lapply pass to unlist.

set.seed(1)
lapply(myList, purrr::compose(unlist, Vectorize(rbeta, SIMP = F)), 
       shape1 = vPar1, shape2 = vPar2)

# [[1]]
# [1] 0.0269188825 0.0074012868 0.0005853054 0.9941391825
# 
# [[2]]
# [1] 0.037118765 0.004534898 0.631806102 0.602790723 0.983948500 0.999301928
Avirulent answered 25/11, 2019 at 22:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.