R:临时覆盖函数和范围/命名空间
Posted
技术标签:
【中文标题】R:临时覆盖函数和范围/命名空间【英文标题】:R: temporarily overriding functions and scope/namespace 【发布时间】:2012-03-12 13:45:36 【问题描述】:考虑以下 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
函数来获得系数的标准误差,其想法是通过临时覆盖 vcov
来使用稳健的 var-cov 矩阵,而无需“手动”执行操作或更改函数.
vcov 和 confint 都是通用函数,我不知道这是否是它无法按预期工作的原因。这不是我感兴趣的具体例子;而是概念课。这是命名空间还是范围“问题”?
【问题讨论】:
【参考方案1】:我们展示了如何使用代理对象来做到这一点(请参阅此document 的代理部分),首先使用proto package,然后不使用:
1) 原型。由于confint.lm
正在调用vcov
,我们需要确保(a)我们对vcov
的新替换是在修改后的confint.lm
的环境中,并且(b)修改后的confint.lm
仍然可以从其访问对象原版的。 (例如confint.lm
在stats中调用了隐藏函数format.perc
,所以如果我们不安排第二点为真,隐藏函数就无法访问。)
为了执行上述操作,我们创建了一个新的confint.lm
,除了它有一个新环境(代理环境),其中包含我们的替换vcov
,其父级是原始confint.lm
环境。下面,代理环境被实现为一个原型对象,这里要知道的关键项目是:(a) 原型对象是环境和 (b) 将函数放置在原型对象中,以显示的方式将其环境更改为该原型对象.此外,为了避免 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)
另一个例子,见例子2here。
2) 环境。没有 proto 的代码有点繁琐(实际上它大约使代码大小翻了一番)但这里是:
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)))
编辑:清晰度的各种改进
【讨论】:
太棒了,我不熟悉 proto 包,但它似乎很有用。我继续阅读小插图,这是一本很好的书。感谢您的努力!【参考方案2】:这是因为函数confint
和vcov
都在命名空间“stats”中。您在此处调用的 confint() 有效地获取了 stats::vcov,这很大程度上是因为这就是名称空间的用途 - 您可以编写自己的版本,但不会损害其他预期的行为。
在您的第一个示例中,您仍然可以安全地调用其他依赖于 stats::lm 并且不会因您的本地修改而感到不安的函数。
【讨论】:
好的,所以除了 class(model)以上是关于R:临时覆盖函数和范围/命名空间的主要内容,如果未能解决你的问题,请参考以下文章