Code like df <- data.frame(x=1:10) y <- 20:29 eval(quote(x+y), env=df) does what you might expect: it looks for x and y in the data.frame, and when it doesn't find y there, it looks in the parent environment. However, sometimes I'd like to construct a single environment out of df, so that I can pass it to nested functions and get the same behaviour. Right now, I get the wrong answer from code like this: f1 <- function(df) { g <- function() { eval(quote(x+y), env=df) } y <- 1:10 g() } f1(df) because the eval looks in the environment of f1, finds y there, and gives me the wrong answer. I can modify f1 so it works: f2 <- function(df) { g <- function(env) { eval(quote(x+y), env=df, enclos=env) } y <- 1:10 g(parent.frame()) } but this means carrying around both parent.frame() and df. I'd like to do this: f3 <- function(df) { env <- as.environment(df) g <- function() { eval(quote(x+y), env=env) } y <- 1:10 g() } and get the same result as from f2(df), but currently as.environment doesn't like to be passed a data.frame. Is there a better way to do the same thing? Duncan Murdoch
Duncan Murdoch wrote:> Code like > > df <- data.frame(x=1:10) > y <- 20:29 > > eval(quote(x+y), env=df) > > does what you might expect: it looks for x and y in the data.frame, > and when it doesn't find y there, it looks in the parent environment. > > However, sometimes I'd like to construct a single environment out of > df, so that I can pass it to nested functions and get the same > behaviour. Right now, I get the wrong answer from code like this: > > f1 <- function(df) { > g <- function() { > eval(quote(x+y), env=df) > } > y <- 1:10 > g() > } > > f1(df) > > because the eval looks in the environment of f1, finds y there, and > gives me the wrong answer. > > I can modify f1 so it works: > > f2 <- function(df) { > g <- function(env) { > eval(quote(x+y), env=df, enclos=env) > } > y <- 1:10 > g(parent.frame()) > } > > but this means carrying around both parent.frame() and df. I'd like > to do this: > > f3 <- function(df) { > env <- as.environment(df) > > g <- function() { > eval(quote(x+y), env=env) > } > > y <- 1:10 > g() > } > > and get the same result as from f2(df), but currently as.environment > doesn't like to be passed a data.frame. Is there a better way to do > the same thing? > > Duncan MurdochI don't think it's easily possibe (but Luke et al. might want to correct me). My dirty solution would be: f4 <- function(df) { env <- new.env() mapply(function(x, y) assign(y, x, envir=env), df, names(df)) g <- function() eval(quote(x+y), env=env) y <- 1:10 g() } f4(df) Uwe
Martin Maechler
2004-Feb-26 10:35 UTC
[Rd] Re: Constructing an environment from a data.frame
[Diverted to R-devel]>>>>> "UweL" == Uwe Ligges <ligges@statistik.uni-dortmund.de> >>>>> on Wed, 11 Feb 2004 11:32:52 +0100 writes:UweL> Duncan Murdoch wrote: >> Code like >> >> df <- data.frame(x=1:10) >> y <- 20:29 >> >> eval(quote(x+y), env=df) >> >> does what you might expect: it looks for x and y in the data.frame, >> and when it doesn't find y there, it looks in the parent environment. >> >> However, sometimes I'd like to construct a single environment out of >> df, so that I can pass it to nested functions and get the same >> behaviour. Right now, I get the wrong answer from code like this: >> >> f1 <- function(df) { >> g <- function() { >> eval(quote(x+y), env=df) >> } >> y <- 1:10 >> g() >> } >> >> f1(df) >> >> because the eval looks in the environment of f1, finds y there, and >> gives me the wrong answer. >> >> I can modify f1 so it works: >> >> f2 <- function(df) { >> g <- function(env) { >> eval(quote(x+y), env=df, enclos=env) >> } >> y <- 1:10 >> g(parent.frame()) >> } >> >> but this means carrying around both parent.frame() and df. I'd like >> to do this: >> >> f3 <- function(df) { >> env <- as.environment(df) >> >> g <- function() { >> eval(quote(x+y), env=env) >> } >> >> y <- 1:10 >> g() >> } >> >> and get the same result as from f2(df), but currently as.environment >> doesn't like to be passed a data.frame. Is there a better way to do >> the same thing? >> >> Duncan Murdoch UweL> I don't think it's easily possibe (but Luke et al. might want to correct UweL> me). My dirty solution would be: UweL> f4 <- function(df) { UweL> env <- new.env() UweL> mapply(function(x, y) assign(y, x, envir=env), df, names(df)) UweL> g <- function() UweL> eval(quote(x+y), env=env) UweL> y <- 1:10 UweL> g() UweL> } UweL> f4(df) I do think the best would be to extend as.environment() to make it work with data.frame and as a matter of fact any list. Uwe's code above env <- new.env() mapply(function(x, y) assign(y, x, envir=env), df, names(df)) would suggest a simplistic R level implementation of as.environment.list(). But then, as.environment() is primitive, and as John Chambers is the author of as.environment() and as he has been travelling recently, I'm addressing this explicitely for further comments. Martin