Skip to content
Prev 68772 / 398506 Next

Reconstruction of a "valid" expression within a function

You are passing just a string to subset().  At the very least you need 
to parse it (but still this does not work easily with subset() -- see 
below).  But are you sure you need to do this?  subset() for dataframes 
already accepts subset expressions involving the columns of the 
dataframe, e.g.:

 > df <- data.frame(x=1:10,y=rep(1:5,2))
 > subset(df, y==2)
   x y
2 2 2
7 7 2
 >

However, it's tricky to get subset() to work with an expression for its 
subset argument.  This is because of the way it evaluates its subset 
expression (look at the code for subset.data.frame()).

 > subset(df, parse(text="df$y==2"))
Error in subset.data.frame(df, parse(text = "df$y==2")) :
         'subset' must evaluate to logical
 > subset(df, parse(text="y==2"))
Error in subset.data.frame(df, parse(text = "y==2")) :
         'subset' must evaluate to logical
 >

It's a little tricky in general passing R language expressions around, 
because many functions that work with expressions work with the 
unevaluated form of the actual argument, rather than with an R language 
expression as the value of a variable.  E.g.:

 > with(df, y==2)
  [1] FALSE  TRUE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE
 > cond <- parse(text="y==2")
 > cond
expression(y == 2)
 > with(df, cond)
expression(y == 2)

One way to make these types of functions work with R language 
expressions as the value of a variable is to use do.call():

 > do.call("with", list(df, cond))
  [1] FALSE  TRUE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE
 >

So, returning to subset(), you can give it an expression that is stored 
in the value of a variable like this:

 > do.call("subset", list(df, cond))
   x y
2 2 2
7 7 2
 >

However, if you're a beginner at R, I suspect that you'll get much 
further if you avoid such meta-language constructs and just find a way 
to make subset() work for you without trying to paste together R 
language expressions.

Hope this helps,

-- Tony Plate
Pascal Boisson wrote: