Вызов веса в lm () внутри функции не оценивается должным образом - PullRequest
5 голосов
/ 12 апреля 2020

Я пишу функцию, которая требует взвешенной регрессии. Я неоднократно получал сообщение об ошибке с параметром weights, и я создал минимальный воспроизводимый пример, который вы можете найти здесь:

wt_reg <- function(form, data, wts) {
  lm(formula = as.formula(form), data = data,
     weights = wts)
}

wt_reg(mpg ~ cyl, data = mtcars, wts = 1:nrow(mtcars))

Это возвращает

Ошибка в eval (extras, data, env): объект 'wts' не найден

Если вы запустите все это отдельно, он будет работать нормально. Я копался в lm, и, похоже, проблема в вызове eval(mf, parent.frame()). Несмотря на то, что wts находится в parent.frame (), он не оценивается правильно в вызове. Вот немного подробнее:

mf назначается так, что он такой же, как

stats::model.frame(formula = as.formula(form), data = data, weights = wts, 
    drop.unused.levels = TRUE)

Когда я запускаю

parent.frame()$wts

, он возвращает цифру c вектор. Но когда я запускаю

eval(stats::model.frame(formula = as.formula(form), data = data, weights = wts, 
    drop.unused.levels = TRUE), parent.frame()) 

, это не так.

Я могу запустить

stats::model.frame(formula = as.formula(parent.frame()$form), 
    data = parent.frame()$data, weights = parent.frame()$wts, 
    drop.unused.levels = TRUE)

, и это работает. Вы можете проверить это сами, если хотите использовать пример сверху.

Есть мысли? Я действительно понятия не имею, что здесь происходит ...

1 Ответ

6 голосов
/ 12 апреля 2020

Формулы особые в R, в которых они не только отслеживают имена символов / переменных, но также отслеживают среду, в которой они были созданы. Проверьте

ff <- mpg ~ cyl
environment(ff)
# <environment: R_GlobalEnv>
foo <- function() {
  ff <- mpg ~ cyl
  environment(ff)
}
foo()
# <environment: 0x0000026172e505d8> private function environment (different each time)

Проблема в том, что lm попытается использовать среду, в которой была создана формула, для поиска переменных, а не родительского фрейма. Поскольку вы создаете формулу в вызове wt_reg, формула сохраняется в глобальной области видимости. Но wts существует только в области действия функции. Вы можете изменить свою функцию, чтобы изменить среду в формуле на локальную функцию, тогда все должно работать

wt_reg <- function(form, data, wts) {
  ff <- as.formula(form)
  environment(ff) <- environment()
  lm(formula = ff, data = data,
     weights = wts)
}

wt_reg(mpg ~ cyl, data = mtcars, wts = 1:nrow(mtcars))

eval(mf, parent.frame), на который вы ссылаетесь в lm(), вызывает model.frame() с вашей формулой , А из описания на странице справки ?model.frame: «Все переменные в формуле, подмножестве и в ... ищутся сначала в данных, а затем в среде формулы (более подробную информацию см. В справке по формуле ()»). и собрал во фрейм данных ". Таким образом, он снова ищет в формуле, а не в кадре вызова.

...