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])
.
CodePudding user response:
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.
CodePudding user response:
Another way to do this is with the function brms::stanvar()
. Take a look at its man page here. This is advantageous because you can change the prior within stanvar()
and refit the model without having to recompile it.
Each call to stanvar()
takes two arguments, the value and a string which is the name of the variable that can be used later on inside prior()
. Then combine each individual variable together using
and pass that to the stanvars
argument of brm()
.
For your example, you could do like so:
prior_params <- stanvar(priors[i, 1], 'prior_mean') stanvar(priors[i, 2], 'prior_sd')
tmp <- prior(normal(prior_mean, prior_sd), nlpar = 'x')
brm(..., prior = tmp, stanvars = prior_params)