From kevin.r.coombes at gmail.com  Thu Nov 11 23:31:35 2010
From: kevin.r.coombes at gmail.com (Kevin R. Coombes)
Date: Thu, 11 Nov 2010 16:31:35 -0600
Subject: [Rd] Evaluation puzzle
In-Reply-To: <201011112008.oABK8xjk025512@punchbuggy.mayo.edu>
References: <201011112008.oABK8xjk025512@punchbuggy.mayo.edu>
Message-ID: <4CDC6EC7.9080208@gmail.com>

Hi Terry,

This may not really be a complete answer, but there seems to be a 
difference in eval'ing an expression compared to eval'ing a call (even 
though both are documented in the help page for eval as working just fine).

If you insert the line
     print(eval(expression(zed), parent.frame()))
into your survexp.test function just above the existing call to "eval", 
this line works just fine.  So it's clear that an _expression_ 
containing "zed" can be evaluated, but evaluating the _call_  via the 
model.frame function fails.

I suspect that the actual evaluation problem lies in the call to
     eval(predvars, data, env)
made inside model.frame.default.   The value of "env" when this function 
is called is defined in an earlier line by
     env <- environment(formula)
Since the formula does not have an environment defined when it is passed 
in, one gets provided within the model.frame.default function.  I edited 
my version of model.frame.default to
     print(ls(env))
just before the call to
     eval(predvars, data, env)
and confirmed that "zed" is not part of that environment.

Now the manual page for formula says that "Formulas created with ~ use 
the environment in which they were created. Formulas created with 
'as.formula' use the env argument for their environment."  Since you are 
passing a character string through to model.frame, and it calls 
"as.formula" without an environment, the formula eventually gets 
evaluated in the context of the model.frame.default function without 
knowing about the environment you gave it.

I think you can fix this by explicitly creating your own 
formula+environment before calling miodel frame.  Specifically, try 
changing the line
     m$formula <- tform
to
     m$formula <- as.formula(tform, env=parent.frame())
and see if that helps.  On my machine, it at least allows
     tfun(tdata)
to run without throwing an error.

Best,
     Kevni


On 11/11/2010 2:08 PM, Terry Therneau wrote:
> The survexp function can fail when called from another function.  The "why" of
> this has me baffled, however.
>
> Here is a simple test case, using a very stripped down version of survexp:
>
> survexp.test<- function(formula, data,
>          weights, subset, na.action, rmap,
>          times,  cohort=TRUE,  conditional=FALSE,
>          ratetable=survexp.us, scale=1, npoints, se.fit,
>          model=FALSE, x=FALSE, y=FALSE) {
>      call<- match.call()
>      m<- match.call(expand.dots=FALSE)
>
>      # keep the first element (the call), and the following selected arguments
>      m<- m[c(1, match(c('formula', 'data', 'weights', 'subset', 'na.action'),
>                        names(m), nomatch=0))]
>      m[[1]]<- as.name("model.frame")
>
>      # Add in the ratetable variables
>      varlist<- attr(ratetable, 'dimid')
>      tform<- paste(deparse(formula), paste(varlist, collapse='+'), sep='+')
>      m$formula<- tform
>
>      print(m)
>      print(ls(parent.frame()))
>      mf<- eval(m, parent.frame())
>
>      names(mf)
>      }
>
> Here is the test data
>
> tdata<- data.frame(age= c(12, 24, 36)*365.25, sex=c(1,2,1),
>                      year=as.Date('1953/03/10', '1960/02/23', '1978/09.22'))
> tfun<- function(mydata) {
>       zed<- 100 + (1:nrow(mydata)) * 20
>       survexp.test(zed ~ 1, data=mydata)
>       }
>
> And the result of the exercise.
>
> % R --vanilla
> R version 2.11.0 (2010-04-22)
>
>> library(survival)    # to pick up the survexp.us data
>> tfun(tdata)
> model.frame(formula = "zed ~ 1+age+sex+year", data = mydata)
> [1] "mydata" "zed"
> Error in eval(expr, envir, enclos) : object 'zed' not found
>
> -----
>   Eval is being called with the expression shown and an environment that
> contains the relevant variables in that expression: zed and mydata.  Yet it
> fails to find the variable zed.
>
>   I don't see anything relevant in the manual pages for either eval or
> model.frame.  I suspect that there is an invisible, undocumented, magic
> argument somewhere.
>
>
> My second problem is a puzzler:
>
>> options(error=recover)
>> tfun(tdata)
> model.frame(formula = "zed ~ 1+age+sex+year", data = mydata)
> [1] "mydata" "zed"
> Error in eval(expr, envir, enclos) : object 'zed' not found
>
> Enter a frame number, or 0 to exit
>
> 1: tfun(tdata)
> 2: survexp.test(zed ~ 1, data = mydata)
> 3: eval(m, parent.frame())
> 4: eval(expr, envir, enclos)
> 5: model.frame(formula = "zed ~ 1+age+sex+year", data = mydata)
> 6: model.frame.default(formula = "zed ~ 1+age+sex+year", data = mydata)
> 7: eval(predvars, data, env)
> 8: eval(expr, envir, enclos)
>
> Selection: 2
> Called from: model.frame.default(formula = "zed ~ 1+age+sex+year", data = mydata)
>
>
>   Why does selecting "2" result in going to frame "6"?
>
> Terry Therneau
>
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel



[Rd] Evaluation puzzle
Kevin R. Coombes