tags:

views:

61

answers:

2

Is it possible, in the expr expression of the with() function, to access the data argument directly? Here's what I mean conceptually:

> print(df)
  result qid     f1     f2     f3
1     -1   1 0.0000 0.1253 0.0000
2     -1   1 0.0098 0.0000 0.0000
3      1   1 0.0000 0.0000 0.1941
4     -1   2 0.0000 0.2863 0.0948
5      1   2 0.0000 0.0000 0.0000
6      1   2 0.0000 0.7282 0.9087
> with(df, subset(.data, select=f1:f3))  # Doesn't work

Of course the above example is kind of silly, but it would be handy for things like this:

with(subset(df, f2>0), foo(qid, vars=subset(.data, select=f1:f3)))

I tried to poke around with environment() and parent.frame() etc., but didn't come up with anything that worked.

Maybe this is really a question about eval(), since that's how with.default() is implemented.

+3  A: 

I tend to invert it, i.e. put the with() outside and have subset() work on its data:

R> data(mtcars)
R> with(subset(mtcars, gear==4), lm(mpg ~ wt)) # no data arg

Call:
lm(formula = mpg ~ wt)

Coefficients:
(Intercept)           wt  
      42.49        -6.86  

This is also a silly example because lm(mpg ~ wt, data=mtcars, subset=gear==4) obviously does the same but you get the drift.

Dirk Eddelbuettel
Ken Williams
+2  A: 

Using parent.frame():

# sample data:
set.seed(2436502)
dfrm <- data.frame(x1 = rnorm(100), x2 = rnorm(100), g1 = sample(letters, 100, TRUE))

# how to use it:
with(subset(dfrm, x1<0), {
    str(parent.frame(2)$data)
    "Hello!"
})

# 'data.frame':   47 obs. of  3 variables:
#  $ x1: num  -0.836 -0.343 -0.341 -1.044 -0.665 ...
#  $ x2: num  0.362 0.727 0.62 -0.178 -1.538 ...
#  $ g1: Factor w/ 26 levels "a","b","c","d",..: 11 4 15 19 8 13 22 15 15 23 ...

How the magic works

Using ls() you can inspect parent.frames:

with(subset(dfrm, x1<0), {
    print(ls())
    print(ls(parent.frame(1)))
    print(ls(parent.frame(2)))
    print(ls(parent.frame(3)))
})
# [1] "g1" "x1" "x2"
# [1] "enclos" "envir"  "expr"  
# [1] "data" "expr"
# [1] "dfrm"

As you can see:

  • parent.frame(3) is base environment (in this case),
  • parent.frame(2) is environment of subset function
  • parent.frame(1) is environment of { function (see ?Paren)
Marek
That's awesome, thanks. Not sure why I didn't figure that out when I was poking around with `parent.frame()`, I guess I didn't try enough levels. So now I can do: `. <- function() parent.frame(3)$data; with(df, subset(.(), select=f1:f3))`Though I guess that's probably a little too zealous. =)
Ken Williams