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 16:17:09 +1000

Charles C. Berry wrote:

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

That nuance was lost on me. Thanks!

-- 
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 - 06:31:26 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 - 07: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