使用带有长变量列表的 R 函数 nls

using R function nls with long list of variables

我正在尝试使用 R 函数 nls 估计非线性模型。

我将用 nls 的 "help" 工具中的一个例子来说明我的问题。

Treated <- Puromycin[Puromycin$state == "treated", ]
weighted.MM <- function(resp, conc, Vm, K)
{
    pred <- (Vm * conc)/(K + conc)
    (resp - pred) / sqrt(pred)
}

Pur.wt <- nls( ~ weighted.MM(rate, conc, Vm, K), data = Treated,
          start = list(Vm = 200, K = 0.1))

在这个例子中,weighted.MM 是一个参数数量非常有限的函数,我可以毫无问题地为我正在使用的模型类型实现类似的方法。

但是,我现在正尝试转向一个更现实的问题,我实际上有几十个参数要传递给函数。我当然可以简单地列举它们,但我觉得这有点笨拙。

我考虑过先将它们放在一个单独的列表中。例如,使用上面的示例,我首先定义:

MyArguments <- list(Vm, K)  

然后将 MyArguments 作为参数传递给函数(并从函数内部访问各个参数)。但是,这不起作用,因为我收到错误消息

Error: object 'Vm' not found

或者,

    MyArguments <- list("Vm", "K") 

weighted.MM1 <- function(resp, conc1, conc.1, thearguments)
{
  conc <- c(conc1, conc.1)
  pred <- (thearguments[[1]] * conc)/(thearguments[[2]] + conc)
  (resp - pred) / sqrt(pred)
}

Pur.wt1 <- nls( ~ weighted.MM1(rate, conc1, conc.1, MyArguments),
                data = lisTreat, start = list(Vm = 200, K = 0.1))

产量:

Error in thearguments[[1]] * conc : 
  non-numeric argument to binary operator
Called from: weighted.MM1(rate, conc1, conc.1, MyArguments)

有什么解决方法吗?

由于您正在寻找参数的值,因此不需要定义它们:请看下面的代码:

weighted.MM1 <- function(resp, conc1, conc.1, thearguments)
{
  conc <- c(conc1, conc.1)
  pred <- (thearguments[1] * conc)/(thearguments[2] + conc)
  (resp - pred) / sqrt(pred)
}
nls( ~ weighted.MM1(rate, conc1, conc.1, MyArguments),
                data = lisTreat, start = list(MyArguments =c( 200, 0.1)))
Nonlinear regression model
  model: 0 ~ weighted.MM1(rate, conc1, conc.1, MyArguments)
   data: lisTreat
MyArguments1 MyArguments2 
   206.83468      0.05461 
 residual sum-of-squares: 14.6

Number of iterations to convergence: 5 
Achieved convergence tolerance: 3.858e-06

我已经尝试根据@Onyambu 的建议实施新的解决方案。

但这又产生了新的问题。

首先,我尝试用 nls 实现一个解决方案。这是我使用的实际代码:

DiffModel <- nls(COPERTFreq ~ CalculateProbaVehChoiceDiffusion(MyArguments, years = RegistYear),
                 data = DataSetForModel , start = list(MyArguments = c(ASC_Mat, ASC_No_Size)))

其中 CalculateProbaVehChoiceDiffusion() 是在别处定义的非线性函数,RegistYear 是常数,MyArguments 是要估计的系数列表,其中 c(ASC_Mat, ASC_No_Size)作为初始值。

这会导致以下错误消息:

Error in numericDeriv(form[[3L]], names(ind), env) : 
  Missing value or an infinity produced when evaluating the model

现在,我在别处读到这个问题可以通过使用 nlsLM 来解决。这会导致出现新的错误消息:

Error in `rownames<-`(`*tmp*`, value = "MyArguments") : 
  length of 'dimnames' [1] not equal to array extent

好的,所以我在调试模式下 运行 再次使用 nls.lm 模型。这表明错误消息源自以下代码行:

names(out$par) <- rownames(out$hessian) <- colnames(out$hessian) <- names(out$diag) <- names(par)

然而,正是通过检查 "out" 对象才清楚问题所在。首先,out$hessian 只是一个标量,而我希望它的行数和列数等于参数数。其次,out$par$MyArguments 表明,除了第一个元素外,MyArguments 的值不会从一次迭代更改为另一次迭代。

这是已知错误还是我必须修改将 MyArguments 传递给函数调用的方式?

请注意,据我所知,当我将 nlsLm 应用于@Onyambu 提供的示例时也会出现此问题:

> undebug(nls.lm)
> Treated <- Puromycin[Puromycin$state == "treated", ]
> 
> lisTreat <- with(Treated,
+                  list(conc1 = conc[1], conc.1 = conc[-1], rate = rate))
> 
> weighted.MM1 <- function(resp, conc1, conc.1, thearguments)
+ {
+   conc <- c(conc1, conc.1)
+   pred <- (thearguments[1] * conc)/(thearguments[2] + conc)
+   (resp - pred) / sqrt(pred)
+ }
> nls( ~ weighted.MM1(rate, conc1, conc.1, MyArguments),
+      data = lisTreat, start = list(MyArguments =c( 200, 0.1)))
Nonlinear regression model
  model: 0 ~ weighted.MM1(rate, conc1, conc.1, MyArguments)
   data: lisTreat
MyArguments1 MyArguments2 
   206.83468      0.05461 
 residual sum-of-squares: 14.6

Number of iterations to convergence: 5 
Achieved convergence tolerance: 3.858e-06
> 
> nlsLM( ~ weighted.MM1(rate, conc1, conc.1, MyArguments),
+        data = lisTreat, start = list(MyArguments =c( 200, 0.1)))
Error in `rownames<-`(`*tmp*`, value = "MyArguments") : 
  length of 'dimnames' [1] not equal to array extent

因此,虽然 nls 适用于此示例,但 nlsLM 不适用,并且会产生与我的代码相同的错误消息。 然后我在调试模式下再次使用 运行 nlsLM nls.lm。在下一行之后,

out <- .Call("nls_lm", par, lower, upper, fn1, jac1, ctrl, 
    new.env(), PACKAGE = "minpack.lm")

我检查了 out 对象并看到:

$par
$par$MyArguments
[1] 244.5117   0.1000


$hessian
[1] 0.02859739

$fvec
 [1] -5.5215487 -0.9787468 -0.5543382 -1.5986605  0.4486608 -0.9651245  0.7020058  1.2419040  1.1430780  0.4488084  1.1445818  1.6121474

$info
[1] 1

$message
[1] "Relative error in the sum of squares is at most `ftol'."

$diag
$diag[[1]]
[1] 0.2077949


$niter
[1] 4

$rsstrace
[1] 112.59784  43.41211  42.89350  42.89349  42.89349

因此,第二个参数的值在4次迭代后没有改变。这可能当然是正确的解决方案。但我发现我的模型也发生了同样的事情,这是一个有趣的巧合。

最终编辑:我终于决定求助于对所有参数的完整列举。正如我在问题陈述中所写,它不是很优雅,但是,至少它适用于 nls.lm (尽管仍然不适用于 nls)。