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

Charles C. Berry cberry at tajo.ucsd.edu
Tue Apr 22 06:09:40 CEST 2008


On Tue, 22 Apr 2008, Gad Abraham wrote:

> 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? ;)

Well, I did say to use that bit of code IN your function.

Like this:

age <- rnorm(30, 50, 10)
cholesterol <- rnorm(30, 200, 25)
ch <- cut2(cholesterol, g=5, levels.mean=TRUE)

fit <- function(ch, age){
   on.exit(detach("design.options"))
   attach(list(), name="design.options")
   d <- data.frame(ch, age)
   assign('dd', datadist(d), pos='design.options')
   options(datadist="dd")
   lrm(ch ~ age, data=d, x=TRUE, y=TRUE)
}

print(fit(ch,age))

HTH,

Chuck



>
> -- 
> 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.
>

Charles C. Berry                            (858) 534-2098
                                             Dept of Family/Preventive Medicine
E mailto:cberry at tajo.ucsd.edu	            UC San Diego
http://famprevmed.ucsd.edu/faculty/cberry/  La Jolla, San Diego 92093-0901



More information about the R-help mailing list