【问题标题】:Object not found error when passing model formula to another function将模型公式传递给另一个函数时找不到对象错误
【发布时间】:2011-11-21 14:37:45
【问题描述】:

我对 R 有一个奇怪的问题,我似乎无法解决。

我尝试编写一个函数,对 R 中的逐步过程选择的模型执行 K 折交叉验证。(我知道逐步过程存在的问题,这纯粹是为了比较目的):)

现在的问题是,如果我定义函数参数 (linmod,k,direction) 并运行函数的内容,它会完美运行。但是,如果我将它作为函数运行,我会收到一条错误消息,提示找不到 datas.train 对象。

我尝试使用 debug() 单步执行该函数,并且该对象显然存在,但 R 表示当我实际运行该函数时它不存在。如果我只是使用 lm() 拟合模型,它可以正常工作,所以我认为这是循环中的 step 函数的问题,而在函数内部。 (尝试注释掉 step 命令,并将预测设置为来自普通线性模型的预测。)

#CREATE A LINEAR MODEL TO TEST FUNCTION
lm.cars <- lm(mpg~.,data=mtcars,x=TRUE,y=TRUE)


#THE FUNCTION
cv.step <- function(linmod,k=10,direction="both"){
  response <- linmod$y
  dmatrix <- linmod$x
  n <- length(response)
  datas <- linmod$model
  form <- formula(linmod$call)

  # generate indices for cross validation
  rar <- n/k
  xval.idx <- list()
  s <- sample(1:n, n) # permutation of 1:n
  for (i in 1:k) {
    xval.idx[[i]] <- s[(ceiling(rar*(i-1))+1):(ceiling(rar*i))]
  }

  #error calculation
  errors <- R2 <- 0

  for (j in 1:k){
     datas.test <- datas[xval.idx[[j]],]
       datas.train <- datas[-xval.idx[[j]],]
       test.idx <- xval.idx[[j]]

       #THE MODELS+
       lm.1 <- lm(form,data= datas.train)
       lm.step <- step(lm.1,direction=direction,trace=0)

      step.pred <- predict(lm.step,newdata= datas.test)
        step.error <- sum((step.pred-response[test.idx])^2)
        errors[j] <- step.error/length(response[test.idx])

        SS.tot <- sum((response[test.idx] - mean(response[test.idx]))^2)
        R2[j] <- 1 - step.error/SS.tot
  }

  CVerror <- sum(errors)/k
  CV.R2 <-  sum(R2)/k

  res <- list()
  res$CV.error <- CVerror
  res$CV.R2 <- CV.R2

return(res)
}


#TESTING OUT THE FUNCTION
cv.step(lm.cars)

有什么想法吗?

【问题讨论】:

  • 似乎存在范围界定问题,如您所知,step(lm.1,direction=direction,trace=0) 找不到 datas.train。我自己看不到问题的原因。将datas.train 分配为全局变量是一种解决方法,但不是特别令人满意的解决方法(datas.train &lt;&lt;- datas[-xval.idx[[j]],])。也许这应该迁移到 StackOverflow?
  • 具体来说,在step() 中调用add1(fit, scope$add, scale = scale, trace = trace, k = k, ...) 会引发错误,其中add1()stats:::add1.lm
  • @jthetzel,确实。我解决类似问题的一种方法是循环内的另一个函数调用是全局分配它。

标签: r formula


【解决方案1】:

当您创建公式时,lm.cars 被分配了自己的环境。除非您明确更改它,否则此环境将保留在公式中。所以当你用formula函数提取公式时,模型的原始环​​境就包含在内了。

我不知道我是否在这里使用了正确的术语,但我认为您需要明确更改函数内公式的环境:

cv.step <- function(linmod,k=10,direction="both"){
  response <- linmod$y
  dmatrix <- linmod$x
  n <- length(response)
  datas <- linmod$model
  .env <- environment() ## identify the environment of cv.step

  ## extract the formula in the environment of cv.step
  form <- as.formula(linmod$call, env = .env) 

  ## The rest of your function follows

【讨论】:

  • 这行得通。我将不得不研究这个环境的东西。 :) 干杯。
【解决方案2】:

另一个可能导致这种情况的问题是,如果将character(字符串vector)传递给lm,而不是formulavectors 没有environment,因此当lmcharacter 转换为formula 时,它显然也没有environment,而不是自动分配本地环境。如果然后使用不在数据参数data.frame 中但在本地函数参数中的对象作为权重,则会收到not found 错误。这种行为不是很容易理解。这可能是一个错误。

这是一个最小的可重现示例。这个函数需要一个data.frame、两个变量名和一个权重向量。

residualizer = function(data, x, y, wtds) {
  #the formula to use
  f = "x ~ y" 

  #residualize
  resid(lm(formula = f, data = data, weights = wtds))
}

residualizer2 = function(data, x, y, wtds) {
  #the formula to use
  f = as.formula("x ~ y")

  #residualize
  resid(lm(formula = f, data = data, weights = wtds))
}

d_example = data.frame(x = rnorm(10), y = rnorm(10))
weightsvar = runif(10)

并测试:

> residualizer(data = d_example, x = "x", y = "y", wtds = weightsvar)
Error in eval(expr, envir, enclos) : object 'wtds' not found

> residualizer2(data = d_example, x = "x", y = "y", wtds = weightsvar)
         1          2          3          4          5          6          7          8          9         10 
 0.8986584 -1.1218003  0.6215950 -0.1106144  0.1042559  0.9997725 -1.1634717  0.4540855 -0.4207622 -0.8774290 

这是一个非常微妙的错误。如果使用browser 进入函数环境,可以很好地看到权重向量,但在lm 调用中却找不到它!

如果使用名称weights 作为权重变量,则该错误变得更加难以调试。在这种情况下,由于lm 找不到权重对象,它默认使用 base 中的函数 weights() 从而引发更奇怪的错误:

Error in model.frame.default(formula = f, data = data, weights = weights,  : 
  invalid type (closure) for variable '(weights)'

别问我花了多少小时才弄明白。

【讨论】:

  • 我刚刚在并行使用 parLapply 时遇到了这个问题。我正在传递一个在 parLapply 之外创建的公式,该公式显然带有它自己的环境。尝试指定权重时,无法识别该参数。解决方案是将公式转回字符,然后转回在本地环境中创建公式的公式(在 parLapply 函数中)。这很奇怪,值得 R 开发人员研究。如果不是因为这条评论,我永远都不会明白。
  • 我已经花了几个小时来解决同样的问题,感谢您如此清楚地描述它。
猜你喜欢
  • 2022-01-22
  • 2020-05-09
  • 2017-06-08
  • 1970-01-01
  • 2018-11-28
  • 1970-01-01
  • 1970-01-01
  • 2017-06-03
  • 2017-12-20
相关资源
最近更新 更多