我正在处理分段包,在函数内调用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
中封装的数据的方式上:它似乎没有在封闭作用域(在本例中是testit
函数)中查找fit
,而是直接跳到全局作用域。
我确信这个问题与R的作用域规则的一些微妙之处有关。如果我能找到一个快速的解决方案,防止我用这个边缘案例困扰包作者,那就太好了。
谢谢,安德鲁。
尝试插入下面标记为##
的行。仍然有一个差异,这没有考虑到,正如运行修改后的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
无需将其设为全局变量。问题实际上出在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
是"到处看,先返回"的懒惰版本。
我联系了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
}
不过,为了澄清起见,应该注意的是,这两位代码做了不同的事情:第二个片段实际上实现了我最初的目的(检查拟合中是否存在统计上显著的中断),而第一个片段则检查是否存在第二个中断。