如何正确地将与具有随机效应的变量名称关联的公式传递到“R”中的拟合回归模型中?

How to correctly pass formulas associated with a variable name with random effects into fitted regression models in `R`?

我目前遇到一个问题,我必须在将它们发送到回归函数之前预先指定我的公式。比如在R中使用stan_gamm4函数,我们有下面的例子:

dat <- mgcv::gamSim(1, n = 400, scale = 2) ## simulate 4 term additive truth
## Now add 20 level random effect `fac'...
dat$fac <- fac <- as.factor(sample(1:20, 400, replace = TRUE))
dat$y <- dat$y + model.matrix(~ fac - 1) %*% rnorm(20) * .5

br <- stan_gamm4(y ~ s(x0) + x1 + s(x2), data = dat, random = ~ (1 | fac), 
                 chains = 1, iter = 200) # for example speed

现在,因为公式和随机公式是明确指定的,那么如果我们调用:

br$call$random
> ~(1 | fac)

我们能够检索随机效应的形式。

现在,让我们保持一切不变,但对随机部分使用一个表达式:

formula.rand <- as.formula( '~(1|fac)' )

那么,如果我们之前做了同样的事情,但是用 formula.rand 代替,我们有:

br <- stan_gamm4(y ~ s(x0) + x1 + s(x2), data = dat, random = formula.rand, 
                     chains = 1, iter = 200) # for example speed

但是现在:我们有:

br$call$random
> formula.rand

代替原来的。许多贝叶斯包都依赖于访问 br$call$random,那么有没有一种方法可以将变量用于公式,让它传入,并在调用 br$call$random 时保留原始关系?谢谢。

如果我理解正确,你的问题不是,stan_gamm4 可能计算了错误的结果(根据我的收集,情况并非如此),而只是 br$call$random 指的是变量名而不是公式。这似乎对模型的进一步 post 处理有问题。

由于 stan_gamm4 在内部使用 match.call 来查找调用,我不知道如何指定不同的模型以获得 "correct" br$call$random正面。但您可以在事后通过以下方式简单地修改它:

br <- stan_gamm4(y ~ s(x0) + x1 + s(x2), data = dat, random = formula.rand) 

br$call$random <- formula.rand
br$call$random
#> ~(1 | fac)

然后继续你正在做的事情。

恕我直言,这不是 stan_gamm4 的问题。在您的第二个示例中,如果您执行

class(br$call$random)

您会看到它属于 class "name"。所以,好像 $call 只是一些包含内容的列表。为了以编程方式访问它,您需要使用

对其进行评估
eval(br$call$random)

为了得到~(1 | fac),也就是class"formula".

虽然我没有使用过 Stan,但这是 R 处理存储调用的方式中固有的问题。你可以看到它发生在 lm,例如:

model <- function(formula)
{
    lm(formula, data=mtcars)
}
m <- model(mpg ~ disp)
m$call$formula
# formula

最简单的解决方案是使用 substitute 构造调用以插入您要保留的实际值,而不是符号名称。在 lm 的情况下,这将类似于

model2 <- function(formula)
{
    call <- substitute(lm(formula=.f, data=mtcars), list(.f=formula))
    eval(call)
}
m2 <- model2(mpg ~ disp)
m2$call$formula
# mpg ~ disp

对于 Stan,你可以做到

stan_call <- substitute(br <- stan_gamm4(y ~ s(x0) + x1 + s(x2), data=dat, random=.rf,
                 chains=1, iter=200),
             list(.rf=formula.rand))
br <- eval(stan_call)