Ошибка объекта не найдена при передаче формулы модели в другую функцию - PullRequest
10 голосов
/ 21 ноября 2011

У меня странная проблема с R, которую я не могу решить.

Я попытался написать функцию, которая выполняет перекрестную проверку в K-кратном порядке для модели, выбранной пошаговой процедуройR. (я знаю о проблемах с пошаговыми процедурами, это чисто для целей сравнения)Содержание функции, работает без нареканий.НО, если я запускаю его как функцию, я получаю сообщение об ошибке, в котором говорится, что объект datas.train не может быть найден.

Я попытался пройти функцию с помощью debug (), и объект явно существует, но R говорит, что это не так, когда я на самом деле запускаю функцию.Если я просто подгоняю модель с помощью lm (), она работает нормально, поэтому я считаю, что это проблема с функцией шага в цикле, когда она внутри функции.(попробуйте закомментировать команду шага и задайте предсказания из обычной линейной модели.)

#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)

Есть мысли?

Ответы [ 2 ]

15 голосов
/ 21 ноября 2011

Когда вы создали свою формулу, 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
8 голосов
/ 28 апреля 2016

Другая проблема, которая может вызвать это, если передать character (строка vector) в lm вместо formula.vector s не имеют environment, и поэтому, когда lm преобразует character в 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 не может найти объект весов, по умолчанию используется функция weights() из base , что приводит к появлению еще более странной ошибки:

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

Don 'не спрашивайте меня, сколько часов мне понадобилось, чтобы понять это.

...