我正在使用分段包,并且在函数内调用davies.test()
时遇到问题。
考虑以下情况:
library(segmented)
data = data.frame(x = 1:21, y = c(10:1, 0:10))
fit = lm(y ~ x, data = data)
fit.seg = segmented(fit, seg.Z = ~ x)
davies.test(fit.seg, seg.Z = ~ x, alternative = "greater")
完美无缺,表明分段回归有两个统计上不同的斜率。
现在,如果我将所有内容打包成这样的函数:
testit <- function() {
data = data.frame(x = 1:21, y = c(10:1, 0:10))
fit = lm(y ~ x, data)
fit.seg = segmented(fit, seg.Z = ~ x)
davies.test(fit.seg, seg.Z = ~ x, alternative = "greater")$p.value
}
testit()
然后它运作正常......
但如果我从全局环境中删除fit
,那么它就会失败。
> rm(fit)
> testit()
Error in eval(expr, envir, enclos) : object 'fit' not found
问题似乎与davies.test
尝试访问fit
中封装的数据的方式有关:它似乎并未在封闭范围内查找fit
(在这种情况下是testit
函数),但直接跳到全局范围。
我确信这个问题与R的范围规则有些微妙关系。如果我能找到一个快速解决方案,可以防止我使用这个边缘案例麻烦包装作者,那就太棒了。
谢谢, 安德鲁。
答案 0 :(得分:4)
尝试插入下面标有##
的行。如果运行修改后的testit
时显示的警告显示但输出pvalue相同,则仍然存在差异,这可能不足以满足您的需求。当然,这是包中的一个错误,如果他们要解决它,最好是向包维护者询问。
library(segmented)
testit <- function() {
data = data.frame(x = 1:21, y = c(10:1, 0:10))
fit = lm(y ~ x, data)
fit.seg = segmented(fit, seg.Z = ~ x)
environment(davies.test) <- environment() ##
davies.test(fit.seg, seg.Z = ~ x, alternative = "greater")$p.value
}
testit()
,并提供:
[1] 0.01858149
Warning message:
In summary.lm(object) : essentially perfect fit: summary may be unreliable
答案 1 :(得分:3)
无需将其变为全局变量。问题实际上在segmented
,而不是davies.test
。它找不到fit
。
您可以使用dynGet
在任何环境中找到fit
,包括调用函数的环境:
testit <- function() {
data = data.frame(x = 1:21, y = c(10:1, 0:10))
fit = lm(y ~ x, data)
fit.seg = segmented(dynGet("fit"), seg.Z = ~ x)
davies.test(fit.seg, seg.Z = ~ x, alternative = "greater")$p.value
}
testit()
这应该按你的意愿行事。
如果在不同的环境中有多个名为fit
的变量,请使用get
(请参阅?get
)指定要从中获取的环境。 dynGet
是“到处寻找;先回归”的懒惰版本。
答案 2 :(得分:1)
我联系了segmented
的作者,他立即回复了。他对原始问题提出的另一个解决方案是
testit <- function() {
data = data.frame(x = 1:21, y = c(10:1, 0:10))
fit = lm(y ~ x, data)
fit.seg = segmented(fit, seg.Z = ~ x)
fit.seg$call$obj<-fit
davies.test(fit.seg, seg.Z = ~ x, alternative = "greater")$p.value
}
但是,他还指出lm
对象实际上应该直接传递给davies.test()
,如下所示:
testit <- function() {
data = data.frame(x = 1:21, y = c(10:1, 0:10))
fit = lm(y ~ x, data)
davies.test(fit, seg.Z = ~ x, alternative = "greater")$p.value
}
为了澄清,应该注意的是,这两行代码做了不同的事情:第二个片段实际上满足了我的原始目的(检查拟合中的统计上显着的中断),而第一个片段检查是否存在是第二次休息。