2

I have a wrapper function for lm in R. I want to modify the weights argument, if called, before passing it to lm. Is there a way to do this?

For example, the wrapper function myfunc should reset the weights to 1, and thus give the same coefficients as an unweighted lm. However, that doesn't happen here:

#Load data
library(MASS)
data(Boston)

#Wrapper function for lm
myfunc <- function(formula, data, ...){
  if (!is.null(weights)){
    weights <- rep(1, nrow(data))
  }
  fit <- lm(formula, data, ...)
  return(fit)
}

#Build functions
myfunc('medv ~ .', Boston)
Call:
lm(formula = formula, data = data)

Coefficients:
(Intercept)         crim           zn        indus         chas          nox           rm          age  
  3.646e+01   -1.080e-01    4.642e-02    2.056e-02    2.687e+00   -1.777e+01    3.810e+00    6.922e-04  
        dis          rad          tax      ptratio        black        lstat  
 -1.476e+00    3.060e-01   -1.233e-02   -9.527e-01    9.312e-03   -5.248e-01  

myfunc('medv~.', Boston, weights=Boston$crim)
Call:
lm(formula = formula, data = data, weights = ..1)

Coefficients:
(Intercept)         crim           zn        indus         chas          nox           rm          age  
  83.809053    -0.117041     0.115602    -0.053765    10.245815   -38.463510    -0.580526     0.035360  
        dis          rad          tax      ptratio        black        lstat  
  -2.163867     0.265246    -0.008546    -1.311419     0.003468    -0.568235  
Gaurav Bansal
  • 5,221
  • 14
  • 45
  • 91

1 Answers1

3

You never actually passed a weights vector to lm(). The ... doesn't just pass any variables you have lying around in your function. And you can't really modify variables in the .... If you want to change them, you need to capture them.

myfunc <- function(formula, data, weights=NULL, ...){
  formula <- as.formula(formula)
  environment(formula) <- environment()
  if (!is.null(weights)){
    weights <- rep(1, nrow(data))
  }
  fit <- lm(formula, data, weights=weights, ...)
  return(fit)
}
MrFlick
  • 195,160
  • 17
  • 277
  • 295
  • 1
    That call throws error: `invalid type (closure) for variable '(weights)` – utubun Jul 02 '18 at 19:34
  • 1
    @utubun I updated the answer. the `lm` function expects the weight variable to be in the same environment as the formula. This fixes that problem. – MrFlick Jul 02 '18 at 20:00
  • Don't you think that for this particular example `function(formula, data, ...){lm(formula, data, weights = NULL, ...)}` is enough to get desired output, even if ellipsis is used in the body of `myfunc`? Probably I just don't understand the question. – utubun Jul 02 '18 at 20:19
  • 1
    @utubun True. In the case that you always want to remove any weights parameter, hard coding the NULL should work without messing with formula environments. But if you try to specify any other sort of weights beside the default, you'd have this problem. – MrFlick Jul 02 '18 at 20:22
  • 1
    I think setting environment is not required here. just specifying `formula <- as.formula(formula)` inside the function is sufficient. – Mankind_008 Jul 02 '18 at 20:34
  • 1
    @Mankind_008. yes. if you pass in a string that's probably true. But if you do pass in ab actual formula (which is normally what one would do) like `myfunc(medv ~ ., Boston)` then it would break again. This should work in all cases. – MrFlick Jul 02 '18 at 20:35
  • @MrFlick +1. yeah that makes sense. – Mankind_008 Jul 02 '18 at 20:39