Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use function arguments in lm formula within function environment

Tags:

r

Consider the following function:

lm_eqn <- function(df, indep, dep){
  
  lm(formula = dep ~ indep, data = df)
}

lm_eqn(iris, Sepal.Length, Sepal.Width)  ## does not work, throws error. 

I tried to quote/unquote in several ways. None of those were succesful, throwing different errors and none of them were exactly helpful for me:

Using deparse(substitute(dep))

Error in contrasts<-(*tmp*, value = contr.funs[1 + isOF[nn]]) : contrasts can be applied only to factors with 2 or more levels

Using quo(dep) or enquo(dep) or expr(dep)

Error in model.frame.default(formula = dep ~ indep, data = df, drop.unused.levels = TRUE) : object is not a matrix

Using above with unquoting using !!:

Error in !dep : invalid argument type

Specifying the variable names for the formula within the function body works:

lm_eqn2 <- function(df){
  
     lm(formula = Sepal.Length ~ Sepal.Width, data = df)
}

lm_eqn2(iris)

# Call:
# lm(formula = Sepal.Length ~ Sepal.Width, data = df)

# Coefficients:
# (Intercept)  Sepal.Width  
#     6.5262      -0.2234 

What am I missing?

like image 326
tjebo Avatar asked Jan 28 '26 13:01

tjebo


1 Answers

If you want to keep the formula in the output pretty, you can call substitute on the whole call, which will interpolate the variable names, then call eval on the result to run it:

lm_eqn <- function(data, x, y){
    eval(substitute(
        lm(formula = y ~ x, data = data)
    ))
}

lm_eqn(iris, Sepal.Width, Sepal.Length)
#> 
#> Call:
#> lm(formula = Sepal.Length ~ Sepal.Width, data = iris)    # <- pretty!
#> 
#> Coefficients:
#> (Intercept)  Sepal.Width  
#>      6.5262      -0.2234

Or to make it all really simple (and a lot more flexible), just pass a formula directly:

lm_frm <- function(data, formula){
    lm(formula, data)
}

lm_frm(iris, Sepal.Length ~ Sepal.Width)
#> 
#> Call:
#> lm(formula = formula, data = data)
#> 
#> Coefficients:
#> (Intercept)  Sepal.Width  
#>      6.5262      -0.2234

Wrapping the lm call in eval(substitute(...)) will fix the stored call structure with this approach, too.

like image 165
alistaire Avatar answered Jan 31 '26 05:01

alistaire



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!