Michael
Michael

Reputation: 13914

Passing Argument to lm in R within Function

I would like to able to call lm within a function and specify the weights variable as an argument passed to the outside function that is then passed to lm. Below is a reproducible example where the call works if it is made to lm outside of a function, but produces the error message Error in eval(expr, envir, enclos) : object 'weightvar' not found when called from within a wrapper function.

olswrapper <- function(form, weightvar, df){
  ols <- lm(formula(form), weights = weightvar, data = df)
  }

df <- mtcars

ols <- lm(mpg ~ cyl + qsec,  weights = gear, data = df)
summary(ols)

ols2 <- olswrapper(mpg ~ cyl + qsec,  weightvar = gear, df = df)
#Produces error: "Error in eval(expr, envir, enclos) : object 'weightvar' not found"

Upvotes: 7

Views: 4245

Answers (3)

Dominik Lenda
Dominik Lenda

Reputation: 86

eval(substitute(...)) inside a body of a function allows us to employ non-standard evaluation

df <- mtcars
olswrapper <- function(form, weightvar, df)
  eval(substitute(ols <- lm(formula(form), weights = weightvar, data = df)))
  summary(ols)

olswrapper(mpg ~ cyl + qsec,  weightvar = gear, df = df)

More here: http://adv-r.had.co.nz/Computing-on-the-language.html

Upvotes: 2

Gabe
Gabe

Reputation: 1812

I know I'm late on this, but I believe the previous explanation is incomplete. Declaring weightvar <- df$gear and then passing it in to the function only works because you use weightvar as the name for your weight argument. This is just using weightvar as a global variable. That's why df$gear doesn't work directly. It also doesn't work if you use any name except weightvar.

The reason why it doesn't work is that lm looks for data in two places: the dataframe argument (if specified), and the environment of your formula. In this case, your formula's environment is R_GlobalEnv. (You can test this by running print(str(form)) from inside olswrapper). Thus, lm will only look in the global environment and in df, not the function environment.

edit: In the lm documentation the description of the data argument says: "an optional data frame, list or environment (or object coercible by as.data.frame to a data frame) containing the variables in the model. If not found in data, the variables are taken from environment(formula), typically the environment from which lm is called."

A quick workaround is to say environment(form) <- environment() to change your formula's environment. This won't cause any problems because the data in the formula is in the data frame you specify.

Upvotes: 2

tospig
tospig

Reputation: 8333

Building on the comments, gear isn't defined globally. It works inside the stand-alone lm call as you specify the data you are using, so lm knows to take gear from df.

Howver, gear itself doesn't exist outside that stand-alone lm function. This is shown by the output of gear

> gear
Error: object 'gear' not found

You can pass the gear into the function using df$gear

weightvar <- df$gear
ols <- olswrapper(mpg ~ cyl + qsec, weightvar , df = df)

Upvotes: 3

Related Questions