如何在 brms 中正确使用 set_prior() 以及从矩阵中提取的值,例如先验(正常(先验[i,1],先验[i,2]))

问题描述 投票:0回答:2

我想创建一组参数用于 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])

r matrix regression brms
2个回答
3
投票

另一种方法是使用函数

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
)

2
投票

基本上,当

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

© www.soinside.com 2019 - 2024. All rights reserved.