我想创建一组参数用于 R 中的 brms 模型:
library(brms)
tmp <- prior(normal(10,2), nlpar = "x")
理想情况下,我想从导入的矩阵中提取每个先验值(例如
normal(10,2)
),例如:
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")
但是,这会产生以下输出:
#b_x ~ normal(priors[i, 1], priors[i, 2])
而不是数值:
#b_x ~ normal(10, 2)
我意识到这可能非常基本,但我无法找出正确的方法来做到这一点。我试过:
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")
有人可以告诉我我哪里出错了吗?按位置 [,] 提取似乎适用于其他函数,例如
lm(priors[,1]~priors[,2])
。
另一种方法是使用函数
brms::stanvar()
。请在此处查看其手册页。这是有利的,因为您可以在 stanvar()
内更改先验并重新拟合模型,而无需重新编译它。因为 brms 是 Stan 的包装器,所以这相当于将先验分布的超参数作为 Stan 模型中 data
块的一部分传递。
对
stanvar()
的每次调用都需要两个参数,即值和一个字符串,该字符串是稍后可以在 prior()
中使用的变量名称。然后使用 +
将每个单独的变量组合在一起,并将其传递给 stanvars
的 brm()
参数。
对于您的示例,您可以这样做:
prior_params <- stanvar(priors[i, 1], 'prior_mean') + stanvar(priors[i, 2], 'prior_sd')
x_prior <- prior(normal(prior_mean, prior_sd), nlpar = 'x')
brm(..., prior = x_prior, stanvars = prior_params)
编辑:您可以将超参数向量传递给
stanvar()
的第一个参数,然后在调用中将该向量索引到prior()
。示例:
my_prior_means <- c(0, 1, 2)
my_prior_sds <- c(1, 2, 3)
prior_params <- stanvar(my_prior_means, 'prior_mean') + stanvar(my_prior_sds, 'prior_sd')
abc_prior <- c(
prior(normal(prior_mean[1], prior_sd[1]), nlpar = 'a'),
prior(normal(prior_mean[2], prior_sd[2]), nlpar = 'b'),
prior(normal(prior_mean[3], prior_sd[3]), nlpar = 'c')
)
dt <- data.frame(x = 1:100, y = runif(100))
brm(
bf(y ~ a / (1 + exp(-b*x + c)), a + b + c ~ 1, nl = TRUE),
prior = abc_prior,
stanvars = prior_params,
data = dt
)
基本上,当
priors[i, 1]
和 priors[i, 2]
传递给 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)
虽然这有效,但当我阅读
?prior
时,我发现建议将分布指定为字符串。因此,以下也有效。
## 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)
注:
我也是 brms 的新手,所以老实说,我认为 其他答案对于这个包来说更原生/自然。 (这就是通过回答问题来学习的好处;我总是从同伴那里得到有用的反馈。)
如上所述,这是推荐的方式,因为它相当于将先验超参数作为数据传递给 Stan 模型的 brms。