Search code examples
rmatrixregressionbrms

How to correctly use set_prior() in brms with values extracted from a matrix, e.g. prior(normal(priors[i,1], priors[i,2]))


I'd like to create a set of parameters for use in a brms model in R:

library(brms)

tmp <- prior(normal(10,2), nlpar = "x")

Ideally I'd like to extract the values for each prior (e.g. normal(10,2)) from an imported matrix, for example:

priors <- cbind(c(10,20,30,40), c(2,4,6,8))

i <- 1
tmp <- prior(normal(priors[i,1], priors[i,2]), nlpar = "x")

However, this gives the following output:

#b_x ~ normal(priors[i, 1], priors[i, 2])

instead of the numeric values:

#b_x ~ normal(10, 2)

I realize this is probably pretty basic, but I can't figure out the correct way to do this. I've tried:

prior(normal(as.numeric(priors[i,1]), as.numeric(priors[i,2])), nlpar = "x")
prior(normal(as.list(priors[i,1]), as.list(priors[i,2])), nlpar = "x")
prior(normal(paste(priors[i,1]), paste(priors[i,2])), nlpar = "x")
prior(normal(get(priors[i,1]), paste(get[i,2])), nlpar = "x")

Can someone show me where I'm going wrong here? extracting by position [,] seems to work for other functions, e.g., lm(priors[,1]~priors[,2]).


Solution

  • Basically, you want to evaluate priors[i, 1] and priors[i, 2] when they are passed to prior().

    priors <- cbind(c(10, 20, 30, 40), c(2, 4, 6, 8))
    
    i <- 1
    
    ## use `do.call()`
    do.call("prior",
            list(prior = call("normal", priors[i, 1], priors[i, 2]),
                 nlpar = "x"))
    #b_x ~ normal(10, 2)
    
    ## use `eval(call())`
    eval(call("prior", call("normal", priors[i, 1], priors[i, 2]), nlpar = "x"))
    #b_x ~ normal(10, 2)
    

    While this works, as I read ?prior, I find that it is recommended to specify distribution as a string. Therefore, the following also works.

    ## I used %d because values in `priors` matrix are integers
    ## in general, it is safer to use %f for real numbers
    eval(call("prior",
              sprintf("normal(%d, %d)", priors[i, 1], priors[i, 2]),
              nlpar = "x"))
    #b_x ~ normal(10, 2)
    

    Note:

    I am also a newbie with brms, so I honestly think the other answer more native/natural to the package. (This is the benefit of learning by answering questions; I always get useful feedback from peers.)

    As said, it is the recommended way, because it is the brms equivalent of passing prior hyperparameters as data to a Stan model.