问题
I am building a wrapper around lm to do some additional calculations. I'd like the wrapper to pass ... to lm, but I am getting into trouble with lm's weights argument.
LmWrapper <- function(df, fmla, ...) {
est <- lm(fmla, df, ...)
list(model = est)
}
If I call the wrapper with a weights argument,
data(airquality)
LmWrapper(airquality, Ozone ~ Wind, weights = Temp)
R does not know where to look for the weights:
Error in eval(expr, envir, enclos) :
..1 used in an incorrect context, no ... to look in
The lm help page says
All of
weights,subsetandoffsetare evaluated in the same way as variables informula, that is first indataand then in the environment offormula.
but the wrapper seems to change things.
How do I fix this?
The traceback() for the above error looks like this:
8: eval(expr, envir, enclos)
7: eval(extras, data, env)
6: model.frame.default(formula = fmla, data = df, weights = ..1,
drop.unused.levels = TRUE)
5: stats::model.frame(formula = fmla, data = df, weights = ..1,
drop.unused.levels = TRUE)
4: eval(expr, envir, enclos)
3: eval(mf, parent.frame())
2: lm(fmla, df, ...) at #2
1: LmWrapper(diamonds, price ~ carat, weights = depth)
Calling lm directly, works just fine:
lm(Ozone ~ Wind, airquality, weights = Temp)
回答1:
So the problem is that lm normally looks up those names in argument data but somehow scoping goes wrong. You can fix that by looking up column references and passing them on manually.
LmWrapper <- function(df, fmla, ...) {
# get names of stuff in ...
argNames = sapply(substitute(list(...))[-1L], deparse)
# look for identical names in df
m = match(names(df), argNames, 0L)
# store other arguments from ... in a list
args = list(eval(parse(text = argNames[-m])))
# name the list
names(args) = names(argNames[-m])
# store complete values in args, instead of just references to columns
# the unlist code is rather ugly, the goal is to create a list where every
# element is a column of interest
args[names(argNames)[m]] = unlist(apply(df[, as.logical(m), drop = FALSE],
2, list), recursive = FALSE)
# also put other stuff in there
args$formula = fmla
args$data = df
# do lm
est = do.call(lm, args)
list(model = est)
}
data(airquality)
airquality$subset = airquality$Solar.R > 200
LmWrapper(airquality, Ozone ~ Wind, weights = Temp, subset = subset,
method = 'qr')
The code above is not the most beautiful, but it works for both subset and weights. Alternatively, you could just handle weights and subset as exceptions.
来源:https://stackoverflow.com/questions/38683076/ellipsis-trouble-passing-to-lm