From murdoch at stats.uwo.ca  Wed May  6 18:47:33 2009
From: murdoch at stats.uwo.ca (Duncan Murdoch)
Date: Wed, 06 May 2009 12:47:33 -0400
Subject: [Rd] Scope question concerning calls within a user defined
	function
In-Reply-To: <4A01B844.2000400@his.com>
References: <4A01B844.2000400@his.com>
Message-ID: <4A01BF25.8060400@stats.uwo.ca>

On 5/6/2009 12:18 PM, Terrence Ireland wrote:
> The following is a simple example with a poor solution that shows my
> difficulties with scope.  The function /logit.test /has 3 arguments:  
> /model.start,/
> an initial model; /model.finish/, an all-inclusive model, /my.data/, a 
> dataset, in
> this case trivial. 
> 
> There are 2 function calls in l/ogit.test,/ first to /glm/ to get an 
> initial fit (local variable
> /logit/) using /model.start;/ then a call to /stepAIC/ using the initial 
> fit.
> 
> I had thought that l/ogit/ would carry along the dataset, /test.data/ 
> for use in
> the call to /stepAIC/.  Instead it complains that it cannot find 
> /my.data/.  It seems
> to have found the name, not the value in the /call/ attribute. 
> 
> I fixed the problem by creating a global variable /my.data/ within the 
> function,
> naming it l/ogit.test.global,/ not a very good solution.
> 
> My question is:  How do I handle scope correctly?

The general principle is this:

Variables in formulas are looked up in the data= argument of a modelling 
function; if that is missing (or the variable was not found), then in 
the environment where the formula was created.

I haven't traced through the code, but I believe stepAIC also uses the 
environment of the formula to find the dataset (i.e. it assumes the 
dataset and formula were created in the same place.

Since you didn't do that, you need some trickery.  You want my.data to 
be found in the environment of the formula.  my.data is local to your 
logit.test function, so changing logit.test to look like this:

logit.test <- function(model.start,model.finish,my.data)
   {
     environment(model.start) <- environment()
     environment(model.finish) <- environment()
     logit <- glm(model.start,binomial(link =
"logit"),my.data,control=glm.control(epsilon=0.0001),x=TRUE,y=TRUE)
     Table <- stepAIC(logit,scope=model.finish,direction="both",trace=1,k=2)
   }

should work.  The only potential problem is if your formulas have 
variables named model.start, model.finish, my.data, logit, or Table: 
those will be found before global variables of the same name.

I would avoid <<- in logit.test.global, and use the same technique there.

Duncan Murdoch

> 
> Thanks,
> 
> Terry Ireland
> 
> Script of Experiment:
> 
>  > library(MASS)
> 
>  > test.data
>   Approve Score OldScore
> 1     Yes     1       12
> 2     Yes     3       10
> 3     Yes     5        8
> 4      No     4        9
> 5      No     6        7
> 6      No     8        5
>  > test.start
> Approve ~ 1
>  > test.finish
> Approve ~ Score + OldScore
>  > logit.test
> function(model.start,model.finish,my.data)
>   {
>     logit <- glm(model.start,binomial(link = 
> "logit"),my.data,control=glm.control(epsilon=0.0001),x=TRUE,y=TRUE);
>     Table <- stepAIC(logit,scope=model.finish,direction="both",trace=1,k=2);
>   }
>  > logit.test.global
> function(model.start,model.finish,my.data)
>   {
>     my.data <<- my.data
>     logit <- glm(model.start,binomial(link = 
> "logit"),my.data,control=glm.control(epsilon=0.0001),x=TRUE,y=TRUE);
>     Table <- stepAIC(logit,scope=model.finish,direction="both",trace=1,k=2);
>   }
> 
>  > logit.test(test.start,test.finish,test.data)

In this call, test.start gets assigned to model.start in the function, 
test.finish to model.finish, and test.data to my.data.  Within 
logit.test, the glm() call looks fine, because you pass my.data to it.  But

> Start:  AIC=10.32
> Approve ~ 1
> 
> Error in inherits(x, "data.frame") : object "my.data" not found
>  > logit.test.global(test.start,test.finish,test.data)
> Start:  AIC=10.32
> Approve ~ 1
> 
>            Df Deviance     AIC
> + Score     1   4.8089  8.8089
> + OldScore  1   4.8089  8.8089
> <none>          8.3178 10.3178
> 
> Step:  AIC=8.81
> Approve ~ Score
> 
>         Df Deviance     AIC
> <none>       4.8089  8.8089
> - Score  1   8.3178 10.3178
>  >
> 
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel



[Rd] Scope question concerning calls within a user defined function
Duncan Murdoch