R: временно перекрывающие функции и область видимости / пространство имен - PullRequest
6 голосов
/ 22 февраля 2012

Рассмотрим следующий код R:

local({
  lm <- function(x) x^2 
  lm(10)
})

Это временно отменяет функцию lm, но как только local будет выполнено, оно "вернется в нормальное состояние". Мне интересно, почему такой же подход не работает в следующем простом примере:

require(car)
model <- lm(len ~ dose, data=ToothGrowth)
local({
  vcov <- function(x) hccm(x) #robust var-cov matrix
  confint(model) # confint will call vcov, but not the above one.
})

Функция confint использует функцию vcov для получения стандартных ошибок для коэффициентов, и идея состоит в том, чтобы использовать надежную матрицу var-cov путем временного переопределения vcov, не делая вещей "вручную" или изменяя функции .

Как vcov, так и confint являются общими функциями, я не знаю, является ли это причиной того, что она не работает как задумано. Это не конкретный пример, который меня интересует как таковой; скорее концептуальный урок. Это пространство имен или область действия "проблема"?

Ответы [ 2 ]

4 голосов
/ 22 февраля 2012

Мы покажем, как это сделать, используя прокси-объекты (см. Раздел «Прокси» этого документа ), сначала используя протопакет , а затем без:

1) прото . Поскольку confint.lm вызывает vcov, мы должны убедиться, что (a) наша новая замена для vcov находится в пересмотренной среде confint.lm и (b) пересмотренный confint.lm все еще может получить доступ к объектам из его оригинал. (Например, confint.lm вызывает скрытую функцию format.perc в статистике, поэтому, если мы не договорились о том, что вторая точка имеет значение true, скрытая функция не может быть доступна.)

Для выполнения вышеизложенного мы создаем новый confint.lm, который является тем же самым, за исключением того, что у него есть новое окружение (прокси-окружение 1020 *), которое содержит замену vcov, и чей родитель в свою очередь является исходным confint.lm среда. Ниже прокси-среда реализована в виде объекта-прототипа, где ключевыми элементами, которые необходимо знать здесь, являются: (а) объекты-прототипы являются средами и (б) размещение функции в объекте-прототипе, как показано, изменяет свою среду на этот объект-прототип , Также, чтобы избежать проблем с отправкой S3 от confint до confint.lm, мы вызываем метод confint.lm напрямую.

Хотя hccm, похоже, не дает никакого другого результата, мы можем убедиться, что он был запущен, заметив вывод trace:

library(car)
library(proto)

trace(hccm)

model <- lm(len ~ dose, data=ToothGrowth)
proto(environment(stats:::confint.lm), # set parent
    vcov = function(x) hccm(x), #robust var-cov matrix
    confint.lm = stats:::confint.lm)[["confint.lm"]](model)

Для другого примера см. Пример 2 здесь .

2) окружение . Код немного более обременительный без прото (на самом деле он примерно удваивает размер кода), но вот он:

library(car)

trace(hccm)

model <- lm(len ~ dose, data=ToothGrowth)
local({
  vcov <- function(x) hccm(x) #robust var-cov matrix
  confint.lm <- stats:::confint.lm
  environment(confint.lm) <- environment()
  confint.lm(model) # confint will call vcov, but not the above one.
}, envir = new.env(parent = environment(stats:::confint.lm)))

РЕДАКТИРОВАТЬ: различные улучшения в четкости

2 голосов
/ 22 февраля 2012

Это происходит потому, что функции confint и vcov находятся в пространстве имен "stats". Вызываемый здесь метод confint () эффективно получает stats :: vcov, в значительной степени потому, что для этого предназначены пространства имен - вам разрешено писать свои собственные версии вещей, но не в ущерб ожидаемому в противном случае поведению.

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

...