Переопределить функцию, которая импортируется в пространство имен
Как 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-объектам это работает, и используется измененный termplot. Но при использовании 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 ответа
Я в тупике - я не могу понять, как 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))
Попробуйте переписать функцию, которую вы вызываете termplot
от. На предположение, это plot.gam
в mgcv
пакет.
Сначала загрузите необходимый пакет.
library(mgcv)
Вот твой заместитель termplot
функция, добавленная к stats
Пространство имен.
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)
Я думаю, что функция trace() автоматически делает то, что было предпринято выше. Делать:
trace('termplot', edit='gedit')
Где "gedit" - это имя текстового редактора. Откроется редактор с исходным кодом, и вы можете вставить любой код замещения, какой пожелаете.
Чтобы вернуться к исходной версии просто untrarace ('termplot')
Предостережение: я пытался использовать это, когда в текстовом редакторе было открыто много файлов, и он не работал. Поэтому я использую текстовый редактор "gedit" в своей системе, который я использую не часто. Таким образом, я уверен, что R откроет новый экземпляр 'gedit'.
Я не уверен, что это поможет, но я думаю, что стоит попробовать. Последовательность поиска, когда есть пространства имен, действительно сбивает с толку.