kurt
kurt

Reputation: 93

how to pass columns in data.frame to functions having dplyr's function inside

x <- y <- 1:5
df = data.frame(m=x,n=y)

myfun <- function(data, var) {
  library(dplyr)
   select(data, var)
}


myfun(df, m)

Error in eval(expr, envir, enclos) : object 'm' not found

Upvotes: 1

Views: 1344

Answers (2)

Patrick Roocks
Patrick Roocks

Reputation: 3259

Richards answer makes it possible to bypass an arbitrary number of arguments. But to control each argument of such a select call separately you have to know: In select(data, m), m is not a variable which has an assigned value at this point! It is just a symbol which gets some meaning in the context of the dataframe "data". myfun(df, m) will fail as soon as the parameter m is used (which is the case in the select-call), because m has no value (or the value from the global environment, which you surely do not want!) Internally, dplyr will use the substitute function to convert it to a symbol (instead of evaluating it). After var is converted to a symbol (or a call, for e.g. selections like m:n), you can compose and evaluate a new select-call with do.call.

For your example code this implies:

x <- y <- 1:5
df = data.frame(m=x,n=y)

myfun <- function(data, var) {
  library(dplyr)
  var <- substitute(var)
  do.call('select', list(data, var))
}


myfun(df, m)

The generalization to more arguments is straight forward.

For an arbitrary number of arguments which you want to convert to symbols or calls you can use

myfun <- function(...) {
  args <- substitute(list(...))
  # Now args[i] is a symbol/call representing the i-th argument
}

Upvotes: 2

Rich Scriven
Rich Scriven

Reputation: 99371

select uses select.data.frame, a data frame method. The second argument to select is a ... list so that arguments can be passed to other methods. Your function uses the name var in its second argument, and because of dplyr's .() function, the base R variance function var is being passed to other functions inside select.

Long story short, change your argument names. I would go with

myfun <- function(z, ...) select(z, ...)
myfun(df, x)
myfun(df, y)

You can also use the select methods

> select.myfun <- function(.data, ...) UseMethod("select")
> myfun(df, exclude = "x")
> methods(select)[6]
[1] "select.myfun"

As a shameless plug, I'll refer you to a question I asked about ... arguments. There are two very good explanations in the answers.

Edit As requested, a look at .()

> `.`
function (..., .env = parent.frame()) 
{
    structure(as.list(match.call()[-1]), env = .env, class = "quoted")
}
<environment: namespace:plyr>

> .(x)
List of 1
 $ x: symbol x
 - attr(*, "env")=<environment: R_GlobalEnv> 
 - attr(*, "class")= chr "quoted"

Upvotes: 0

Related Questions