[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