Вызов веса в lm () внутри функции не оценивается должным образом

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

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

он возвращает числовой вектор. Но когда я бегу

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)

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

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


person be_green    schedule 11.04.2020    source источник


Ответы (1)


Формулы являются особенными в 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: «Все переменные в формуле, подмножестве и в ... сначала ищутся в данных, а затем в среде формулы (дополнительные сведения см. В справке по формуле ()) и собираются во фрейм данных ". Таким образом, он снова смотрит в среду формулы, а не в вызывающий фрейм.

person MrFlick    schedule 11.04.2020
comment
Значит, вызов parent.frame() в eval(mf, parent.frame) не делает того, что я думаю? - person be_green; 12.04.2020
comment
Это все еще не работает для меня. См .: `` wt_reg ‹- function (form, data, wts) {form = as.formula (form) lm (formula = form, data = data, weights = wts)} wt_reg (mpg ~ cyl, data = mtcars, wts = 1: nrow (mtcars)) `` - person be_green; 12.04.2020
comment
Я также отмечу, что он прекрасно может найти аргументы data и form! Если я сделаю такие вещи без аргументов в пользу веса, это сработает. - person be_green; 12.04.2020
comment
Что именно вы имеете в виду, говоря, что все еще не работает? Ваш код в комментарии не переназначает среду, поэтому он не решает проблему. as.formula не изменит среду для вещей, которые уже являются формулами. Я добавил немного о том, почему eval(mf, parent.frame()) не делает то, что вы думаете. Он отлично работает без весов, потому что все эти объекты находятся в глобальной среде. - person MrFlick; 12.04.2020
comment
О нет, ваша версия работает! Я до сих пор не понимаю почему. - person be_green; 12.04.2020
comment
Меня поразило, что мне не нужно явно вызывать среду, если я создаю формулу вне функции. Или что аргумент данных должен сломаться. - person be_green; 12.04.2020
comment
Я просто не могу понять, почему ff <- as.formula(form , env = environment()) не работает. - person Ian Campbell; 12.04.2020
comment
Потому что as.formula предназначен для принуждения к вещам, которые еще не являются формулами. Если вы передадите что-то, что уже является формулой, это не изменит ее. Этот код будет работать, если вы передадите формулу в виде строки, например: wt_reg("mpg ~ cyl", ...). Тогда принуждение к формуле будет использовать эту среду. - person MrFlick; 12.04.2020
comment
Ах, я полагаю, я мог бы просто посмотреть на источник и понять это. Спасибо. - person Ian Campbell; 12.04.2020