Переопределить функцию, которая импортируется в пространство имен - PullRequest
27 голосов
/ 06 июня 2011

Поскольку функция termplot в R содержит какой-то странный код, который вызывает у меня досадные ошибки, я хочу переопределить его в своем собственном тестовом коде, пока не найду более постоянное решение. Проблема в том, что измененная функция не загружается пакетом mgcv. Пакет mgcv загружает termplot из пакета stats в его пространство имен, используя importFrom() в файле NAMESPACE.

Как мне убедить mgcv использовать измененный термплот? Я попробовал:

unlockBinding("termplot", as.environment("package:stats"))
assign("termplot", my.termplot, as.environment("package:stats"))
lockBinding("termplot", as.environment("package:stats"))

и применительно к lm-объектам это работает, и используется измененный термплот. Но при использовании gam-объектов, созданных пакетом mgcv, это не работает. Я не собираюсь собирать пакет статистики из исходного кода, если смогу избежать этого ...

Чтобы уточнить, я тоже пытался с

assignInNamespace("termplot", my.termplot, ns="stats")
assignInNamespace("termplot", my.termplot, ns="mgcv")

во всех возможных комбинациях, до подключения mgcv, после подключения mgcv, и мне не удалось заставить его работать.


РЕДАКТИРОВАТЬ:

Я перепробовал все варианты, приведенные здесь (кроме перекомпиляции любого пакета), и не смог заставить его работать. Самый простой способ для меня - использовать функцию-обертку. Это обсуждение можно найти здесь . Спасибо за все советы.


Воспроизводимый пример:

my.termplot <- function (x) print("my new termplot")

  unlockBinding("termplot", as.environment("package:stats"))
  assignInNamespace("termplot", my.termplot, ns="stats", envir=as.environment("package:stats"))
  assign("termplot", my.termplot, as.environment("package:stats"))
  lockBinding("termplot", as.environment("package:stats"))


y <- 1:10
x <- 1:10
xx <- lm(y~x)
termplot(xx)
require(mgcv)
dat <- gamSim(1, n = 400, dist = "normal", scale = 2)
b <- gam(y ~ s(x0) + s(x1) + s(x2) + x3, data = dat)
plot(b,all=TRUE)

plot.gam вызывает termplot для негладких терминов (в данном случае x3), но не может найти новую функцию termplot.


EDIT2: по-видимому, мой пример работает. Теперь я вижу, что решил свой собственный вопрос: в первом коде я не добавил ни пространства имен, ни пакета в assignInNamespace. Важно помнить, чтобы изменить функцию как в пространстве имен, так и в пакете, прежде чем загружать другой пакет. Спасибо @hadley за то, что он указал мне правильное направление, @Marek за то, что он проверил код и сообщил, что он работает, а остальное за то, что он попытался ответить.

Ответы [ 3 ]

11 голосов
/ 09 июня 2011

Я в замешательстве - я не могу понять, как plot.gam находит termplot - насколько я могу судить, он не использует обычные правила видимости. Похоже, для этого требуется более глубокое понимание пространств имен, чем у меня сейчас.

my.termplot <- function (x) print("my new termplot")

# where is it defined?
getAnywhere("termplot")
# in package and in namespace

unlockBinding("termplot", as.environment("package:stats"))
assign("termplot", my.termplot, "package:stats")

unlockBinding("termplot", getNamespace("stats"))
assign("termplot", my.termplot, getNamespace("stats"))

getAnywhere("termplot")[1]
getAnywhere("termplot")[2]
# now changed in both places

y <- 1:10
x <- 1:10 + runif(10)
xx <- lm(y ~ x)
termplot(xx) # works

library("mgcv")
b <- gam(y ~ s(x), data = data.frame(x, y))
plot(b) # still calls the old termplot

# I'm mystified - if try and find termplot as
# seen from the environment of plot.gam, it looks 
# like what we want
get("termplot", environment(plot.gam)) 
3 голосов
/ 06 июня 2011

Попробуйте переписать функцию, из которой вы звоните termplot.Предположительно, это plot.gam в пакете mgcv.

Сначала загрузите необходимый пакет.

library(mgcv)

Вот ваша альтернативная функция termplot, добавленная к stats namespace.

my.termplot <- function (model, ...) 
{
  message("In my.termplot")
}

unlockBinding("termplot", as.environment("package:stats"))
assign("termplot", my.termplot, as.environment("package:stats"))
lockBinding("termplot", as.environment("package:stats"))

Аналогично, вот функция-обертка, добавленная к пространству имен mgcv.

my.plot.gam <- function (x, ...) 
{
  message("In my.plot.gam")
  my.termplot()
}

unlockBinding("plot.gam", as.environment("package:mgcv"))
assign("plot.gam", my.plot.gam, as.environment("package:mgcv"))
lockBinding("plot.gam", as.environment("package:mgcv"))

Вот пример для тестирования, взятый из ?gam.

dat <- gamSim(1, n = 400, dist = "normal", scale = 2)
b <- gam(y ~ s(x0) + s(x1) + s(x2) + s(x3), data = dat)
plot(b) 
2 голосов
/ 06 июня 2011

Я думаю, что функция trace () автоматически выполняет то, что было сделано выше.Do:

trace('termplot', edit='gedit')

Где 'gedit' - это имя текстового редактора.Откроется редактор с исходным кодом, и вы можете вставить любой код замещения, какой пожелаете.

Чтобы вернуться к исходной версии, просто отследите ('termplot')

Предостережение.в текстовом редакторе было открыто много файлов, и он не работал.Поэтому я использую текстовый редактор «gedit» в своей системе, который я использую не часто.Таким образом, я уверен, что R откроет новый экземпляр 'gedit'.

Я не уверен, что это поможет, но я думаю, что стоит попробовать.Последовательность поиска при наличии пространств имен действительно сбивает с толку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...