2

I'm creating a package that uses non-standard evaluation to keep track of the meaning of columns. The package passes a data frame among functions, which do various things do the same set of columns. Nonstandard evaluation works great for this:

my_select <- function(df, xcol, ycol) {
    new_df <- dplyr::select(df, !!xcol, !!ycol)
    new_df
}
my_select(mtcars, quo(wt), quo(mpg))

However, I'd like a function that works with a formula:

my_lm <- function(df, xcol, ycol) {
    new_lm <- lm(!!xcol, !!ycol, data=df)
    new_lm
}
my_lm(mtcars, quo(wt), quo(mpg)

returns Error in !xcol : invalid argument type. I've tried all sorts of combinations of quo(), enquo(), and !!, but the basic problem is that I don't know what kind of object lm needs.

Drew Steen
  • 16,045
  • 12
  • 62
  • 90
  • I can get around this problem as follows: `new_lm <- lm(unlist(select(df, !!xcol)) ~ unlist(select(df, !!ycol)))` but this is pretty inelegant, and the problem remains that I don't understand how non standard evaluation works with data frames – Drew Steen Oct 19 '17 at 19:28

2 Answers2

2

You can create a formula by pasting the values of the equation together, then pass the formula to lm. I'm sure there's a better way to do this, but here's one working approach:


library(rlang)

my_lm <- function(df, xcol, ycol) {
  form <- as.formula(paste(ycol, " ~ ", xcol)[2])
  my_lm <- lm(form, data=df)
  my_lm
}

my_lm(mtcars, quo(wt), quo(mpg))
#> 
#> Call:
#> lm(formula = form, data = mtcars)
#> 
#> Coefficients:
#> (Intercept)           wt  
#>      37.285       -5.344
zlipp
  • 790
  • 7
  • 16
1

@zlipp gave a working answer, but here is a more updated version

my_lm <- function(df, xcol, ycol) {
  xcol_e <- rlang::enquo(xcol)
  ycol_e <- rlang::enquo(ycol)
  form <- paste0(rlang::as_label(ycol_e), "~", rlang::as_label(xcol_e))
    new_lm <- lm(form, data=df)
    new_lm
}
my_lm(mtcars, wt, mpg)

Using rlang instead of paste

my_lm <- function(.df, xcol, ycol) {
  form <- rlang::new_formula(rlang::ensym(ycol), rlang::ensym(xcol)) 
  new_lm <- lm(form, data=.df) 
  new_lm
}
my_lm(mtcars, wt, mpg)
Harlan Nelson
  • 1,394
  • 1
  • 10
  • 22
  • How might the `rlang` version work with multiple xcol, or should I post this as a new question? Eg. `xcols_e <- lang::enquos(...)` and `form <- paste0(rlang::as_label(ycol_e), "~", paste(sapply(xcols_e, rlang::as_label), collapse = "+"))`. – JWilliman Aug 12 '20 at 23:16