使用带有长变量列表的 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)。
我正在尝试使用 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)。