I'm building a package that will:
- read in a data set
- determine which components are needed to model the data1
- build a self-starting NLS model using those components
- apply that model to the data
The result is stored in a list that contains the data, model, and nls result. Everything works until step 4. I've stored my constructed models in the list, and R no longer recognizes them as selfStart functions.
Here's a toy example illustrating my problem. The following function (from the SSlogis
manual) works fine at top-level:
Chick.1 <- ChickWeight[ChickWeight$Chick == 1, ]
fm1 <- nls(weight ~ SSlogis(Time, Asym, xmid, scal), data = Chick.1)
fm1
Nonlinear regression model
model: weight ~ SSlogis(Time, Asym, xmid, scal) data: Chick.1
Asym xmid scal
937.02 35.22 11.41
residual sum-of-squares: 76.66Number of iterations to convergence: 0
Achieved convergence tolerance: 7.778e-07
But when I store the function and data together in a list, R doesn't see the selfstarting function as selfstarting anymore:
myobj <- list()
myobj$model <- SSlogis
myobj$data <- ChickWeight[ChickWeight$Chick == 1, ]
nls(weight ~ myobj$model(Time, Asym, xmid, scal), data = myobj$data)
Error in getInitial.default(func, data, mCall = as.list(match.call(func, :
no 'getInitial' method found for "function" objects
My workflow will eventually include processing dozens of datasets, so I'd like to keep each dataset and its associated model in its own object (and these objects will probably end up in a list of objects). Is there some way to maintain or restore the environment of my selfStart functions even after they're stored inside another list?
UPDATE
In response to Gregor's suggestion, I tried this:
nls(as.formula(sprintf("weight ~ %s(Time, Asym, xmid, scal)",
"myobj$model")), data = myobj$data)
Error in nls(as.formula(sprintf("weight ~ %s(Time, Asym, xmid, scal)", :
singular gradient In addition: Warning message:
In nls(as.formula(sprintf("weight ~ %s(Time, Asym, xmid, scal)", :
No starting values specified for some parameters.
Initializing ‘Asym’, ‘xmid’, ‘scal’ to '1.'.
Consider specifying 'start' or using a selfStart model
Update 2
Inspired by @Gregor I came up with a workaround:
nlsDispatch <- function(obj){
GLOBAL_NLS <<- obj$model
nls(weight ~ GLOBAL_NLS(Time, Asym, xmid, scal), data = myobj$data)
}
nlsDispatch(myobj)
Nonlinear regression model
model: weight ~ GLOBAL_NLS(Time, Asym, xmid, scal)
data: myobj$data
Asym xmid scal
937.02 35.22 11.41
residual sum-of-squares: 76.66Number of iterations to convergence: 0
Achieved convergence tolerance: 6.621e-07
That works, but dropping my function into the global environment is ugly. And it suggests that if I had a better handle on environments I should be able to avoid abusing the global environment to get this done.
1: In my application, this is mostly a matter of counting peaks, and figuring out how many Normal curves are needed to model them.