nls selfStart 函数的范围

Scope of nls selfStart functions

我正在构建一个包,它将:

  1. 读入一个数据集
  2. 确定对数据建模需要哪些组件1
  3. 使用这些组件构建自启动 NLS 模型
  4. 将该模型应用于数据

结果存储在包含数据、模型和 nls 结果的列表中。一切正常,直到第 4 步。我已将构建的模型存储在列表中,R 不再将它们识别为 selfStart 函数。

这是一个说明我的问题的玩具示例。以下函数(来自 SSlogis 手册)在顶层运行良好:

 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.66

Number of iterations to convergence: 0
Achieved convergence tolerance: 7.778e-07

但是当我将函数和数据一起存储在一个列表中时,R 不再将自启动函数视为自启动:

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

我的工作流程最终将包括处理数十个数据集,因此我想将每个数据集及其关联模型保存在其自己的对象中(这些对象可能最终会出现在对象列表中)。有什么方法可以维护或恢复我的 selfStart 函数的环境,即使它们存储在另一个列表中也是如此?

更新

为了响应 Gregor 的建议,我尝试了这个:

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

更新 2

受@Gregor 的启发,我想出了一个解决方法:

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.66

Number of iterations to convergence: 0
Achieved convergence tolerance: 6.621e-07

这行得通,但是将我的函数放到全局环境中很难看。它表明,如果我能更好地处理环境,我应该能够避免滥用全局环境来完成这项工作。

1:在我的应用程序中,这主要是计算峰值的问题,并计算出需要多少条正态曲线为他们建模。

1) 这有效:

Model <- myobj$model
nls(weight ~ Model(Time, Asym, xmid, scal), data = myobj$data)

给予

Nonlinear regression model
  model: weight ~ Model(Time, Asym, xmid, scal)
   data: myobj$data
  Asym   xmid   scal 
937.02  35.22  11.41 
 residual sum-of-squares: 76.66

Number of iterations to convergence: 0 
Achieved convergence tolerance: 6.621e-07

2) 对于自启动函数来说,范围界定确实是一团糟。问题出现在使用此行的 getInitial.formula 中:

func <- get(as.character(object[[2L]][[1L]]))

请注意 get(环境)没有第二个参数,因此它不关注环境。

因此,如果您想将上面的解决方案放在一个函数中,那么您需要像这样解决它:

f <- function() {
  myobj <- list()
  myobj$model <- SSlogis
  myobj$data <- ChickWeight[ChickWeight$Chick == 1, ]
  Model <<- myobj$model
  nls(weight ~ Model(Time, Asym, xmid, scal), data = myobj$data)
}
f()

3) 另一个解决方法是附加模型。这将使它远离全局工作区。请注意,我们之后将其分离,因此函数不会留下任何痕迹。

f2 <- function() {
  on.exit(detach())
  if (any(grepl("list", search()))) stop("list already on search path")
  myobj <- list()
  myobj$model <- SSlogis
  myobj$data <- ChickWeight[ChickWeight$Chick == 1, ]
  attach(list(Model = myobj$model))
  nls(weight ~ Model(Time, Asym, xmid, scal), data = myobj$data)
}
f2()

请注意,如果 detach 没有发生,那么下次 attach 完成时,搜索列表中将附加两个项目(而在先前的方法中,它总是覆盖全局变量,这样就不会发生)所以我们检查搜索路径上是否没有这样的列表,如果有则停止并报错。