在R中为nls模型获取正确的起始值


12

我试图将一个简单的幂定律模型拟合到如下数据集:

mydf

rev     weeks
17906.4 1
5303.72 2
2700.58 3
1696.77 4
947.53  5
362.03  6

目标是使电源线通过并使用它来预测rev未来几周的赞誉。大量的研究使我找到了该nls功能,我按如下方式实现了该功能。

newMod <- nls(rev ~ a*weeks^b, data=modeldf, start = list(a=1,b=1))
predict(newMod, newdata = data.frame(weeks=c(1,2,3,4,5,6,7,8,9,10)))

虽然这适用于lm模型,但会出现singular gradient错误,我理解这与我的初始值a和有关b。我尝试了不同的值,甚至可以在Excel中进行绘制,传递一个孤行,获取一个方程式,然后使用该方程式中的值,但仍然遇到错误。我看着一堆像答案的这一个,并试图在第二个答案(看不惯第一),但都没有结果。

我真的可以在这里找到有关如何找到正确的起始值的帮助。或者,我可以使用什么其他功能代替nls。

如果您想mydf轻松地重新创建:

mydf <- data.frame(rev=c(17906.4, 5303.72, 2700.58 ,1696.77 ,947.53 ,362.03), weeks=c(1,2,3,4,5,6)) 

1
尽管用R表示(实际上必须用某种语言表示),但如何找到合适的非线性模型拟合起始值已经足够统计,因此在IMO中就成为话题。例如,它实际上不是编程问题。
gung-恢复莫妮卡

Answers:


13

这是非线性最小二乘模型的常见问题。如果您的起始值与最佳值相差很远,即使算法在最佳值附近表现良好,也可能无法收敛。

如果从两边的对数开始并拟合线性模型,则可以得到和估计值作为斜率和截距(9.947和-2.011)(编辑:这是自然对数)log(a)b

如果使用这些值来指导和的起始值,一切似乎都可以正常进行:ab

 newMod <- nls(rev ~ a*weeks^b, data=mydf, start = list(a=exp(9.947),b=-2.011))
 predict(newMod, newdata = data.frame(weeks=c(1,2,3,4,5,6,7,8,9,10)))
 [1] 17919.2138  5280.7001  2584.0109  1556.1951  1050.1230   761.4947   580.3091   458.6027
 [9]   372.6231   309.4658

这非常有帮助,非常感谢!我确实有一个关于您如何在此处获得“ a”值的问题。我尝试运行lm(log10(rev)〜log10(weeks)),然后使用“摘要”功能,虽然得到相同的“ b”值,但我的“ a”值却达到4.3201。您做了什么不同才能得出a = 9.947?
NeonBlueHair 2015年

注意,我曾经exp将其恢复为未记录的值,这是表明我使用了普通log函数的线索。只要与使用的日志和反日志保持一致,您将获得相同的起始值答案。因此,您可以以10为底,而我可以以底,一切都一样。e
Glen_b-恢复莫妮卡

啊,你完全正确。我的业余错误。继续思考数学符号,期望“ log”表示对数为10,自然对数为“ ln”。感谢您的澄清。
NeonBlueHair 2015年

1
对于许多数学家(和许多统计学家)来说,未经修饰的“对数”是自然对数,就像对弧度函数的未经修饰的论点是弧度一样。[不幸的是,冲突的约定可能会引起混乱,但是,例如,当我开始使用R时,由于R和我共享相同的约定,因此我对使用log函数并没有三思而后行。]
Glen_b -Reinstate Monica

4

尝试

 newMod <- nls(rev ~ a*weeks^b, data=mydf, startlist(a=17919.2127344,b=-1.76270557120))

我被要求扩大这个答案。这个问题是如此简单,我很惊讶nls无法解决它。但是,真正的问题在于整个R方法和非线性模型拟合的原理。在现实世界中,将x缩放到-1和1之间,将y和y缩放到0和1之间(y = ax ^ b)。那可能足以使nls收敛。当然,正如Glen指出的,您可以拟合相应的对数线性模型。这依赖于以下事实:存在一个简单的变换,可以线性化模型。通常情况并非如此。像nls这样的R例程的问题在于它们不提供对模型重新参数化的支持。在这种情况下,重新参数化很简单,只需重新缩放/重心x和y。但是,通过拟合模型,用户将拥有与原始参数不同的参数a和b。虽然很容易从中计算出原始参数,但另一个困难是,获取这些参数估计值的估计标准偏差通常并不那么简单。这是通过delta方法完成的,该方法涉及对数似然的Hessian和一些导数。非线性参数估计软件应自动提供这些计算,以便轻松支持模型的重新参数化。软件应该支持的另一件事是阶段的概念。您可以考虑首先将模型与Glen的版本拟合为阶段1。“真实”模型适合阶段2。另一个困难是,获取这些参数估计值的估计标准偏差通常并不那么简单。这是通过delta方法完成的,该方法涉及对数似然的Hessian和一些导数。非线性参数估计软件应自动提供这些计算,以便轻松支持模型的重新参数化。软件应该支持的另一件事是阶段的概念。您可以考虑首先将模型与Glen的版本拟合为阶段1。“真实”模型适合阶段2。另一个困难是,获取这些参数估计值的估计标准偏差通常并不那么简单。这是通过delta方法完成的,该方法涉及对数似然的Hessian和一些导数。非线性参数估计软件应自动提供这些计算,以便轻松支持模型的重新参数化。软件应该支持的另一件事是阶段的概念。您可以考虑首先将模型与Glen的版本拟合为阶段1。“真实”模型适合阶段2。非线性参数估计软件应自动提供这些计算,以便轻松支持模型的重新参数化。软件应该支持的另一件事是阶段的概念。您可以考虑首先将模型与Glen的版本拟合为阶段1。“真实”模型适合阶段2。非线性参数估计软件应自动提供这些计算,以便轻松支持模型的重新参数化。软件应该支持的另一件事是阶段的概念。您可以考虑首先将模型与Glen的版本拟合为阶段1。“真实”模型适合阶段2。

我使用支持自然阶段的AD模型构建器来适应您的模型。在第一阶段,仅估计a。这将您的模型带入球场。在第二阶段,估计a和b以获得解。AD Model Builder通过delta方法自动为模型参数的任何函数计算标准偏差,从而鼓励对模型进行稳定的重新参数化。


2

Levenberg-Marquardt算法可以帮助:

modeldf <- data.frame(rev=c(17906.4, 5303.72, 2700.58 ,1696.77 ,947.53 ,362.03), weeks=c(1,2,3,4,5,6))

require(minpack.lm)
fit <- nlsLM(rev ~ a*weeks^b, data=modeldf, start = list(a=1,b=1))

require(broom)
fit_data <- augment(fit)

plot(.fitted~rev, data=fit_data)

1

以我的经验,找到NLR模型参数的初始值的好方法是使用进化算法。从搜索空间中初始估计数(100个)的随机估计(父母)中,选择最佳的20个(后代),并使用它们来帮助定义后续定居中的搜索。重复直到收敛。无需梯度或粗麻布,只需进行SSE评估即可。如果您不太贪婪,这通常会起作用。人们经常遇到的问题是,他们正在使用本地搜索(Newton-Raphson)来执行全局搜索的工作。与往常一样,为手头的工作使用正确的工具是一个问题。使用EA全局搜索来查找牛顿本地搜索的起始值,然后将其减小到最小是更有意义的。但是,与所有事物一样,细节在于魔鬼。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.