Reputation: 3823
I am trying to write a simple iterative reweighted least squares algorithm in R. I want to pass a function as argument for the calculation of the weights, but unfortunately R complains that the function cannot be found. Any ideas what I am doing wrong? Thanks in advance!
Here is my code:
irls <- function(imodel, wfunc, tol) {
repeat {
b0 <- imodel$coef
imodel <- lm(formula(imodel), weights=wfunc(imodel), data=imodel$model)
b1 <- imodel$coef
if(abs((b1-b0)/b0)<=tol) break
}
imodel
}
and a silly example to demonstrate the problem
x <- 1:100
y <- x + rnorm(100)
mlm <- lm(y~x-1)
irls(mlm, function(x){rep(1,length(x$fit))},0.001) # error: wfunc not found
Upvotes: 9
Views: 2609
Reputation: 32391
The formula
contains the environment of the initial lm
call (.GlobalEnv
, in this case),
in which wfunc
was not available.
As a workaround, you can replace it with the current environment.
irls <- function(imodel, wfunc, tol) {
f <- formula(imodel)
environment(f) <- environment()
repeat {
b0 <- imodel$coef
imodel <- lm(f, weights=wfunc(imodel), data=imodel$model)
b1 <- imodel$coef
if(abs((b1-b0)/b0)<=tol) break
}
imodel
}
irls(mlm, function(x){rep(1,length(x$fit))},0.001)
Upvotes: 5
Reputation: 49448
This issue arises because model.frame.default
is called inside lm
, which evaluates everything in the environment of the formula:
model.frame.default
#function (formula, data = NULL, subset = NULL, na.action = na.fail,
# drop.unused.levels = FALSE, xlev = NULL, ...)
#{
#...
# env <- environment(formula)
#...
# extras <- eval(extras, data, env) <-- this is where you run into a problem
#...
So like the others have suggested, evaluate the function outside of lm
.
Upvotes: -1
Reputation: 61963
The issue comes up with how lm looks for the data. If you change the function to this it seems to work
irls <- function(imodel, wfunc, tol) {
repeat {
b0 <- imodel$coef
dat <- imodel$model
dat$wts <- wfunc(imodel)
imodel <- lm(formula(imodel), weights=wts, data=dat)
b1 <- imodel$coef
if(abs((b1-b0)/b0)<=tol) break
}
imodel
}
Upvotes: 8