Re: [R] eval and parent.frame [was: Error in Design package: dataset not found for options(datadist)]

From: Gad Abraham <gabraham_at_csse.unimelb.edu.au>
Date: Tue, 22 Apr 2008 13:15:37 +1000

Charles C. Berry wrote:
> On Sat, 19 Apr 2008, Gad Abraham wrote:
>

>> Charles C. Berry wrote:
>>>  On Fri, 18 Apr 2008, Gad Abraham wrote:
>>>
>>> >  Frank E Harrell Jr wrote:
>>> > >  Gad Abraham wrote:
>>> > > >  Hi,
>>> > > > > > >  Design isn't strictly an R base package, but maybe 
>>> someone can > > >  explain
>>> > > >  the following.
>>> > > > > > >  When lrm is called within a function, it can't find the 
>>> dataset dd:
>>> > > > > > > >  library(Design)
>>> > > > >  age <- rnorm(30, 50, 10)
>>> > > > >  cholesterol <- rnorm(30, 200, 25)
>>> > > > >  ch <- cut2(cholesterol, g=5, levels.mean=TRUE)
>>> > > > >  fit <- function(ch, age)
>>> > > >  + {
>>> > > >  +    d <- data.frame(ch, age)
>>> > > >  +    dd <- datadist(d)
>>> > > >  +    options(datadist="dd")
>>> > > >  +    lrm(ch ~ age, data=d, x=TRUE, y=TRUE)
>>> > > >  + }
>>> > > > >  fit(ch, age)
>>> > > >  Error in Design(eval(m, sys.parent())) :
>>> > > >     dataset dd not found for options(datadist=)
>>> > > > > > >  It works outside a function:
>>> > > > >  d <- data.frame(ch, age)
>>> > > > >  dd <- datadist(d)
>>> > > > >  options(datadist="dd")
>>> > > > >  l <- lrm(ch ~ age, data=d, x=TRUE, y=TRUE)
>>> > > > > > > > > >  Thanks,
>>> > > >  Gad
>>> > > > >  My guess is that you'll need to put dd in the global 
>>> environment, not > >  in
>>> > >  fit's environment.  At any rate it is inefficient to call 
>>> datadist > >  every
>>> > >  time.  Why not call it once for the whole data frame containing 
>>> all > >  the
>>> > >  predictors, at the top of the program?
>>> > >  This is just sample code, in practice the datadist will be 
>>> different for
>>> >  each invocation of the function.
>>> > >  I think it boils down to this behaviour, which I don't 
>>> understand ---
>>> >  although ls can see x in the parent of f2, eval cannot:
>>>
>>>
>>>  That is because (from ?eval):
>>>
>>>  "Objects to be evaluated can be of types call or expression or name 
>>> (when
>>>  the name is looked up in the current scope and its binding is
>>>  evaluated)..."
>>>
>>>  And 'x' is of type name (aka 'symbol').
>>>
>>>  So eval never gets around to looking in 'p', because it never 
>>> succeeded in
>>>  looking up 'x' and evaluating its binding in the current scope.
>>>
>>>  What you probably want is
>>>
>>>      b <- evalq( x, envir=p)
>>>
>>
>> Thanks, that solves the problem with this sample code, but not with 
>> the Design::lrm function, because there are several more layers of 
>> evaluation there.
>>
>> I can get around that with the ugly hack of setting a global NULL 
>> datadist and assigning to it with "<<-" within the fit function every 
>> time, so it's always visible to Design. But it's still an ugly hack :)

>
> Well, the ultimate problem is here
>
> <from Design>
> XDATADIST <- .Options$datadist
> if (length(XDATADIST)) {
> if (!exists(XDATADIST))
> stop(paste("dataset", XDATADIST, "not found for
> options(datadist=)"))
> ...
>
> exists() mandates that there be an object as.name(XDATADIST) in the
> search() list. And a further eval(as.name(XDATADIST)) also requires this.
>
> Another way to do make your function work is to use this in it:
>
> on.exit( detach("design.options") )
> attach(list(), name= "design.options" )
> d <- data.frame(ch, age)
> assign('dd', datadist(d), pos='design.options')
>
> Admittedly still a hack, but it keeps your function from messing around
> with .GlobalEnv, and unless you are willing to rewrite lrm and Design,
> this is what you are stuck with.

I've changed the original example to:

library(Design)
attach(list(), name="design.options")
on.exit(detach("design.options"))
age <- rnorm(30, 50, 10)
cholesterol <- rnorm(30, 200, 25)
ch <- cut2(cholesterol, g=5, levels.mean=TRUE)

fit <- function(ch, age) [

    d <- data.frame(ch, age)
    assign('dd', datadist(d), pos='design.options')     options(datadist="dd")
    lrm(ch ~ age, data=d, x=TRUE, y=TRUE) }

fit(ch, age)

This works when I paste it into the R console, but not when I source() the script:

 > library(Design)
Loading required package: Hmisc
...

 > attach(list(), name="design.options")
 > on.exit(detach("design.options"))
 > age <- rnorm(30, 50, 10)
 > cholesterol <- rnorm(30, 200, 25)
 > ch <- cut2(cholesterol, g=5, levels.mean=TRUE)
 > fit <- function(ch, age)
+ {
+    d <- data.frame(ch, age)
+    assign('dd', datadist(d), pos='design.options')
+ options(datadist="dd")
+ lrm .... [TRUNCATED]
 > fit(ch, age)
Error in as.environment(pos) :

   no item called "design.options" on the search list

Or is that asking for too much? ;)

-- 
Gad Abraham
Dept. CSSE and NICTA
The University of Melbourne
Parkville 3010, Victoria, Australia
email: gabraham_at_csse.unimelb.edu.au
web: http://www.csse.unimelb.edu.au/~gabraham

______________________________________________
R-help_at_r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-help
PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
and provide commented, minimal, self-contained, reproducible code.
Received on Tue 22 Apr 2008 - 03:18:46 GMT

Archive maintained by Robert King, hosted by the discipline of statistics at the University of Newcastle, Australia.
Archive generated by hypermail 2.2.0, at Tue 22 Apr 2008 - 05:30:30 GMT.

Mailing list information is available at https://stat.ethz.ch/mailman/listinfo/r-help. Please read the posting guide before posting to the list.

list of date sections of archive