R:暂时覆盖函数和范围/命名空间

发布于 2025-01-08 02:59:07 字数 591 浏览 0 评论 0原文

考虑以下 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 都是通用函数,我不知道这是否是它无法按预期工作的原因。这不是我感兴趣的具体例子;而是概念性的课程。这是命名空间还是范围“问题”?

Consider the following R code:

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

This temporarily overrides the lm function, but once local has been executed it will "be back to normal". I am wondering why the same approach does not seem to work in this next simple example:

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.
})

The confint function uses the vcov function to obtain standard errors for the coefficients, and the idea is to use a robust var-cov matrix by temporarily overriding vcov, without doing things "manually" or altering functions.

Both vcov and confint are generic functions, I don't know if this is the reason it does not work as intended. It is not the specific example I am interested in as such; rather the conceptual lesson. Is this a namespace or a scope "issue"?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

甜中书 2025-01-15 02:59:07

我们展示了如何使用代理对象执行此操作(请参阅本文档的代理部分) ,首先使用proto 包,然后不使用:

1) proto。由于 confint.lm 正在调用 vcov,我们需要确保 (a) 我们对 vcov 的新替换位于修订后的 confint 中。 lm 的环境和 (b) 修改后的 confint.lm 仍然可以访问其原始对象。 (例如,confint.lm 调用 stats 中的隐藏函数 format.perc,因此如果我们没有安排第二点为 true,则无法访问隐藏函数.)

为了执行上述操作,我们创建一个新的 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)

有关另一个示例,请参见示例 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)))

编辑:清晰度方面的各种改进

We show how to do this using proxy objects (see Proxies section of this document), first using the proto package and then without:

1) proto. Since confint.lm is calling vcov we need to ensure that (a) our new replacement for vcov is in the revised confint.lm's environment and (b) the revised confint.lm can still access the objects from its original. (For example, confint.lm calls the hidden function format.perc in stats so if we did not arrange for the second point to be true that hidden function could not be accessed.)

To perform the above we make a new confint.lm which is the same except it has a new environment (the proxy environment) which contains our replacment vcov and whose parent in turn is the original confint.lm environment. Below, the proxy environment is implemented as a proto object where the key items to know here are: (a) proto objects are environments and (b) placing a function in a proto object in the way shown changes its environment to be that proto object. Also to avoid any problems from S3 dispatch of confint to confint.lm we call the confint.lm method directly.

Although the hccm does not seem to have any different result here we can verify that it was run by noticing the output of the 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)

For another example, see example 2 here.

2) environments. The code is a bit more onerous without proto (in fact it roughly doubles the code size) but here it is:

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)))

EDIT: various improvements in clarity

〗斷ホ乔殘χμё〖 2025-01-15 02:59:07

这是因为函数 confintvcov 都位于命名空间“stats”中。您在此处调用的 confint() 有效地获取 stats::vcov,很大程度上是因为这就是命名空间的用途 - 您可以编写自己的版本,但不会损害其他预期的行为。

在第一个示例中,您仍然可以安全地调用依赖 stats::lm 的其他函数,并且不会因本地修改而感到不安。

This is because the functions confint and vcov are both in the namespace "stats". The confint() you call here effectively gets stats::vcov, pretty much because that is what namespaces are for - you are allowed to write your own versions of things but not to the detriment of otherwise expected behaviour.

In your first example, you can still safely call other functions that rely on stats::lm and that will not get upset by your local modification.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文