【问题标题】:anova test fails on lme fits created with pasted formulaanova 测试在使用粘贴公式创建的 lme 拟合上失败
【发布时间】:2011-12-01 18:45:24
【问题描述】:

我经常通过将我需要的部分粘贴在一起来为模型拟合函数(如lmlme)指定公式参数,如@DWin 对这个问题的回答:Understanding lm and environment

实际上,这看起来像这样:

library(nlme)
set.seed(5)
ns <- 5; ni <- 5; N <- ns*ni
d <- data.frame(y=rnorm(N),
                x1=rnorm(N),
                x2=factor(rep(1:ni, each=ns)),
                id=factor(rep(1:ns, ni)))

getm <- function(xs) {
  f <- paste("y ~", paste(xs, collapse="+"))
  lme(as.formula(f), random=~1|id, data=d, method="ML")
}
m1 <- getm("x1")
m2 <- getm(c("x1", "x2"))

但是,对于 nlme 包中的 lme,比较使用 anova 构建的两个模型不起作用,因为 anova.lme 会查看保存的公式参数以确保模型适合相同的响应,保存的公式参数只是as.formula(f)。错误是:

> anova(m1, m2)
Error in inherits(object, "formula") : object 'f' not found

这是anova 命令应该做的事情(重新调整模型使其工作):

> m1 <- lme(y~x1, random=~1|id, data=d, method="ML")
> m2 <- lme(y~x1+x2, random=~1|id, data=d, method="ML")
> anova(m1, m2)
   Model df      AIC      BIC    logLik   Test  L.Ratio p-value
m1     1  4 76.83117 81.70667 -34.41558                        
m2     2  8 72.69195 82.44295 -28.34597 1 vs 2 12.13922  0.0163

有什么建议吗?

【问题讨论】:

    标签: r


    【解决方案1】:

    这是一个似乎有效的技巧:

    getm <- function(xs) {
      f <- paste("y ~", paste(xs, collapse="+"))
      m <- lme(as.formula(f), random=~1|id, data=d, method="ML")
      m$call$fixed <- eval(m$call$fixed)
      m
    }
    

    但我一点也不喜欢。我非常希望看到这个问题的更有原则的答案,因为我在尝试扩展 bbmle 包时一直遇到此类问题。

    【讨论】:

    • 也许“真正的”解决方案是让 lme 检查公式是如何传递的,并确保它使用 eval 正确存储,就像您所做的那样?
    • 也许吧,但我不确定我知道如何正确地做到这一点。我不知道正确的咒语(甚至逻辑,这是真正的问题)在正确的环境中评估公式,因为它可能已经通过一系列调用函数传递下来......
    • @Ben -- 基于my question and answer here 和 Aaron 的有用指针,我想我可能偶然发现了“正确的方法”。用formula(terms(x)) 替换nlme:::formula.lme(当前为eval(x$call$fixed))的主体似乎是更好的方法,并且确实解决了引起OP 问题的范围问题。 (我使用fixInNamespace("formula.lme", "nlme") 进行了测试,之后anova(m1, m2) '刚刚工作'。
    【解决方案2】:

    Ben 的回答有效,但 do.call 提供了他希望的更通用的解决方案。

    getm <- function(xs) {
        f <- as.formula(paste("y ~", paste(xs, collapse="+")))
        do.call("lme", args = list(f, random=~1|id, data=d, method="ML"))
    }
    

    之所以有效,是因为(默认情况下)args = 中的参数在传递给 lme 之前已经过评估。

    【讨论】:

    • 是的,但是......(这不是 OP 提出的问题)......我真的很好奇 lme(或其他一些独立函数)应该如何表现,以便它可以利用在其他(不再可直接访问)环境中构建的公式
    • 听起来是个有趣的问题。您能否将其作为一个问题提出来,并附上一些代码来说明情况?
    • @BenBolker:我也想知道你的问题的答案。有没有成功地制定它?
    • 使用data=as.name("d")而不是data=d会将调用存储为data=d而不是存储数据帧的表示;这对于使用 update 的对象大小和重用都很有用。
    • @Aaron 这是一个很棒的附录,对我的情况很有帮助。我注意到在使用 do.call() 时我的速度仍然明显下降,这导致我使用 this answer - 使用 quote=T 可以更快地执行,并保持公式不变。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-20
    • 2020-08-29
    相关资源
    最近更新 更多