The function of accessing data from the environment

I am working with a segmented package and ran into a problem when calling davies.test() from inside a function.

Consider the following situation:

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

This works great and indicates that segmented regression has two statistically different slopes.

Now, if I pack it all in a function like this:

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

Then it works fine ...

But if I remove fit from the global environment, this will not work.

 > rm(fit) > testit() Error in eval(expr, envir, enclos) : object 'fit' not found 

The problem is that davies.test trying to access the data encapsulated in fit : it doesn't seem to look for fit in the scope (in this case, testit ), but it passes directly to the global scope.

I am sure that the problem is due to some subtlety with the rules for defining R. If I find a quick fix that would prevent me from bothering the author of the package with this case, that would be great.

Thanks Andrew.

+6
source share
3 answers

Try inserting the line labeled ## below. There is still a difference in that this is not taken into account, as shown by the warning that appears when the modified testit , but the output pvalue is the same, which may be enough for your needs. This, of course, is a bug in the package, and it would be best to ask the maintainer if they fix it.

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

giving:

 [1] 0.01858149 Warning message: In summary.lm(object) : essentially perfect fit: summary may be unreliable 
+4
source

No need to make a global variable. The problem is actually in segmented , not davies.test . It does not find fit .

You can use dynGet to find fit in any environment, including the calling function environment:

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

This should work the way you plan.

If you have several variables named fit in different environments, use get (see ?get ) to indicate which environment you want to get it from. dynGet is all over the place, return the first lazy version.

+3
source

I contacted the author segmented and he quickly answered. Another solution that he proposed to the original question would be

 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 } 

However, he also pointed out that the lm object should actually be passed directly to davies.test() as follows:

 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 } 

For clarification, however, it should be noted that these two bits of code do different things: the second fragment really fulfills my original goal (checking for a statistically significant fit gap), while the first fragment checks to see if this is the second gap.

+1
source

All Articles