【问题标题】:update() inside a function only searches the global environment?函数内部的 update() 只搜索全局环境?
【发布时间】:2012-11-21 07:52:26
【问题描述】:

我尝试编写一个包装函数来批量进行似然比测试。我试图包含 update() 来更新初始模型。但是,似乎不是在函数内部查找对象,而是在全局环境中查找对象。

fake <- data.frame(subj= rep(1:5, 4), 
                   factor1 = rep(LETTERS[c(1,2,1,2)], each=5), 
                   factor2 = rep(letters[1:2], each=10), 
                   data=sort(rlnorm(20)))

foo <- function(){
                  temp <- fake
                  model1 <- lmer(data~factor1*factor2 + (1 |subj), temp)
                  model1a <- update(model1, ~.-factor1:factor2)
                  model1a}

它在下面给出了一条错误消息:

Error in eval(expr, envir, enclos) : object 'factor1' not found

无论如何要在函数中进行 update() 搜索吗?谢谢!

编辑:

我犯了一个错误。我想将“temp”传递给 lmer,而不是“fake”。

编辑2: 建议的一种方便的解决方案是简单地指定数据对象。虽然 update() 现在对此没有任何问题,但 anova() 似乎认为我试图比较的模型是基于不同的数据对象

 foo <- function(){
                  temp <- fake
                  model1 <- lmer(data~factor1*factor2 + (1 |subj), data=temp)
                  model1a <- update(model1, ~.-factor1:factor2, data=temp)
                  anova(model1, model1a)
            }
 foo()

我收到一条错误消息:

 Error in anova(model1, model1b) : 
   all models must be fit to the same data object

我想这个错误超出了 update() 的范围。但我想知道是否有人知道如何解决这个问题。请注意,如果我在不使用 update() 的情况下编写函数,而是拼出模型(见下文),上面的错误就会消失:

 foo <- function(){
                  temp <- fake
                  model1 <- lmer(data~factor1*factor2 + (1 |subj), data=temp)
                  model1a <- lmer(data~factor1 + factor2 + (1 |subj), data=temp)
                  anova(model1, model1a)
            }
 foo()

 Data: temp
 Models:
 model1a: data ~ factor1 + factor2 + (1 | subj)
 model1: data ~ factor1 * factor2 + (1 | subj)
         Df     AIC    BIC  logLik  Chisq Chi Df Pr(>Chisq)  
 model1a  5 -4.6909 3.7535  7.3454                           
 model1   6 -8.8005 1.3327 10.4003 6.1097      1    0.01344 *
 ---
 Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 

编辑 3: 似乎问题出在 anova() 上。我也尝试了@hadley 的建议

foo2 <- function(){
  my_update <- function(mod, formula = NULL, data = NULL) {
  call <- getCall(mod)
  if (is.null(call)) {
    stop("Model object does not support updating (no call)", call. = FALSE)
  }
  term <- terms(mod)
  if (is.null(term)) {
    stop("Model object does not support updating (no terms)", call. = FALSE)
  }
  if (!is.null(data)) call$data <- data
  if (!is.null(formula)) call$formula <- update.formula(call$formula, formula)
  env <- attr(term, ".Environment")
  eval(call, env, parent.frame())}

      model1 <- lmer(data~factor1*factor2 + (1 |subj), temp)
      model1a <- my_update(model1, ~.-factor1:factor2)
      anova(model1, model1a)
 }
 foo2()

我收到如下所示的错误消息:

 Error in as.data.frame.default(data) : 
   cannot coerce class 'structure("mer", package = "lme4")' into a data.frame

【问题讨论】:

  • 对我有用,在 R 2.15.1 中没有错误,除了需要加载 lme4 包
  • 您是否要将temp 传递给lmer 而不是fake
  • 对不起,是的,我想将 temp 传递给 lmer,而不是假的
  • 对于它的价值,这对我来说在lme4(带有object 'temp' not found)的CRAN(稳定)版本上失败了,但在开发版本上成功了(在github上:github.com/lme4/lme4)。开发版中 GLMM 的稳定性存在一些问题,但据我所知,开发版在功能和鲁棒性方面优于稳定版 ...
  • 在编辑时签到——就其价值而言,anova() 示例似乎也适用于开发 lme4。

标签: r function environment


【解决方案1】:

我以前也被这种行为所困扰,所以我编写了自己的update 版本。它评估公式环境中的所有内容,因此它应该相当健壮。

my_update <- function(mod, formula = NULL, data = NULL) {
  call <- getCall(mod)
  if (is.null(call)) {
    stop("Model object does not support updating (no call)", call. = FALSE)
  }
  term <- terms(mod)
  if (is.null(term)) {
    stop("Model object does not support updating (no terms)", call. = FALSE)
  }

  if (!is.null(data)) call$data <- data
  if (!is.null(formula)) call$formula <- update.formula(call$formula, formula)
  env <- attr(term, ".Environment")

  eval(call, env, parent.frame())
}

library(nlme4)

fake <- data.frame(
  subj = rep(1:5, 4), 
  factor1 = rep(LETTERS[c(1,2,1,2)], each = 5), 
  factor2 = rep(letters[1:2], each = 10), 
  data = sort(rlnorm(20)))

foo <- function() {
  temp <- fake
  model1 <- lmer(data ~ factor1 * factor2 + (1 | subj), fake)
  model1a <- my_update(model1, ~ . - factor1:factor2)
  model1a
}
foo()

【讨论】:

  • 现在看来问题出在 anova() 上。我尝试了您的方法,该方法在模型更新方面效果很好。但是,当我尝试使用 anova() 时,它给了我一条错误消息,如我原始帖子的 EDIT 3 所示。感谢您的帮助!
  • @AlexH.,哈德利的回答是去这里的路。它以适用于anova 的方式传递公式和数据组件。在上面的foo2 函数中,您忽略了创建对象temp,添加后对我有用。
【解决方案2】:

虽然我真的很喜欢@Hadley 的回答(并且我自己可能会使用该函数),但您也可以在update 函数中指定data 参数。 (在这里,我假设您想将 temp 传递给您的模型。)

model1a <- update(model1, ~.-factor1:factor2, data = temp)

编辑

如果您希望将模型与 anova 进行比较,update 将伪造 data 参数的名称和“诡计”anova 以相信这两个模型适合使用两个不同的数据集。仅更新公式并创建新模型将避免这种情况:

foo <- function(){
                  temp <- fake
                  model1 <- lmer(data~factor1*factor2 + (1 |subj), data=temp)
                  newForm <- update.formula(formula(model1), ~.-factor1:factor2)
                  model1a <- lmer(newForm, data=temp)
                  anova(model1, model1a)
            }

【讨论】:

  • 但是......我认为这实际上适用于稳定的lme4(我同意它应该)......?
  • @BenBolker,有趣的问题。在发布之前,我在 OSX 上使用 R 2.15.2 使用(我很确定)lme4 的常规 CRAN Mac 二进制版本成功测试了答案。它也适用于 WinXP 上的 R 2.15.2,使用 lme4_0.999999-0Matrix_1.0-9
  • 对不起,我误解了你在做什么。
  • 似乎 anova() 将使用 update() 更新的对象视为基于不同的数据集(请参阅我在原始帖子中添加的示例)。你有办法解决这个问题吗?谢谢!
猜你喜欢
  • 1970-01-01
  • 2012-10-20
  • 1970-01-01
  • 2013-09-24
  • 2020-07-24
  • 2018-02-16
  • 2017-09-12
  • 1970-01-01
  • 2014-02-06
相关资源
最近更新 更多