【问题标题】:R: Trouble fitting a 4-parameter hockeystick curve with nlsR:无法用 nls 拟合 4 参数曲棍球曲线
【发布时间】:2014-09-11 13:09:57
【问题描述】:

我的数据集:

mydata<-structure(list(t = c(0.208333333, 0.208333333, 0.208333333, 0.208333333, 
1, 1, 1, 1, 2, 2, 2, 2, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 
16, 16, 0.208333333, 0.208333333, 0.208333333, 0.208333333, 1, 
1, 1, 1, 2, 2, 2, 2), parent = c(1.2, 1.4, 0.53, 1.2, 1, 0.72, 
0.93, 1.1, 0.88, 0.38, 0.45, 0.27, 0.057, 0.031, 0.025, 0.051, 
0.027, 0.015, 0.034, 0.019, 0.017, 0.025, 0.024, 0.023, 0.29, 
0.22, 0.34, 0.19, 0.12, 0.092, 0.41, 0.28, 0.064, 0.05, 0.058, 
0.043)), .Names = c("t", "Ct"), row.names = c(325L, 326L, 
327L, 328L, 341L, 342L, 343L, 344L, 357L, 358L, 359L, 360L, 373L, 
374L, 375L, 376L, 389L, 390L, 391L, 392L, 401L, 402L, 403L, 404L, 
805L, 806L, 807L, 808L, 821L, 822L, 823L, 824L, 837L, 838L, 839L, 
840L), class = "data.frame")

要拟合的函数是曲棍球曲线;即它在弯曲点 tb 之后变平:

hockeystick<-function (t, C0, k1, k2, tb) 
{
  Ct = ifelse(t <= tb, C0 -k1 * t, C0 -k1*tb -k2*t)
}

使用 nls 拟合:

start.hockey<-c(C0=3,k1=1,k2=0.1,tb=3)
nls(log(Ct)~hockeystick(t,C0,k1,k2,tb),start=start.hockey,data=mydata)

无论我使用什么起始值,我总是得到这个错误:

Error in nlsModel(formula, mf, start, wts) : 
  singular gradient matrix at initial parameter estimates

我尝试了port 和标准的nls 方法。我尝试了模型的线性化(如图所示)和正常状态,但似乎都不起作用。

编辑:根据 Carl 的建议,我尝试将模型拟合到一个数据集,在该数据集中我首先对每个 t 值的 Ct 值进行平均,但仍然得到错误。

编辑:稍微改变了模型,所以k2 的值是正的而不是负的。负值在动力学上没有意义。

【问题讨论】:

  • 尝试绘制 hockeystick(mydata$t,C0,k1,k2,tb)mydata$t 。这不是曲棍球棒。此外,t 的重复值几乎肯定会导致回归失败。
  • 所以一般来说,我最好将回归拟合到每个 t 值的平均值?曲棍球棒是线性化的,所以 y 轴是对数单位。
  • tb 是曲棍球模型的“弯曲点”,即曲线改变其“下降率”的点。

标签: r curve-fitting nls


【解决方案1】:

我还没有完全解决nls() 的问题,但我有一些建议。

首先,我建议稍微修改一下你的曲棍球棒功能,让它在断点处连续:

hockeystick<-function (t, C0, k1, k2, tb) 
{
   Ct <- ifelse(t <= tb, C0 -k1 * t, C0 -k1*t -k2*(t-tb))
}

目测:

par(las=1,bty="l") ## cosmetic
plot(log(Ct)~t,data=mydata)
curve(hockeystick(x,C0=0,k1=0.8,k2=-0.7, tb=3),add=TRUE)

我在这里将k2 设为负数,因此第二阶段的下降斜率小于

start.hockey <- c(C0=0,k1=0.8,k2=-0.7, tb=3)
nls(log(Ct)~hockeystick(t,C0,k1,k2,tb),
                        start=start.hockey,data=mydata)

带有断点的模型在参数上通常是不可微的,但是 我不太明白这是怎么回事……

这确实有效:

library(bbmle)
m1 <- mle2(log(Ct)~dnorm(hockeystick(t,C0,k1,k2,tb),
                  sd=exp(logsd)),
          start=c(as.list(start.hockey),list(logsd=0)),
          data=mydata)

参数合理(与起始值不同):

coef(summary(m1))
##         Estimate Std. Error   z value        Pr(z)
## C0    -0.4170749  0.2892128 -1.442104 1.492731e-01
## k1     0.6720120  0.2236111  3.005271 2.653439e-03
## k2    -0.5285974  0.2400605 -2.201934 2.766994e-02
## tb     2.0007688  0.1714292 11.671108 1.790751e-31
## logsd -0.2218745  0.1178580 -1.882558 5.976033e-02

情节预测:

pframe <- data.frame(t=seq(0,15,length=51))
pframe$pred <- predict(m1,newdata=pframe)
with(pframe,lines(t,pred,col=2))

【讨论】:

  • 感谢您的全面回答。是的,您从tbt-tb 的修改是一个很大的改进。我会在今晚晚些时候回家时查看您的其余答案。
  • 您能否解释一下为什么将dnorm 函数包裹在hockeystick() 周围进行估算?此外,对于这个特定的化合物,我可能需要获取t... 的 2-10 范围内的数据
  • 另外,似乎tb 参数在拟合过程中根本没有改变。我在 hockey.start 中使用的任何值都保留在最终参数集中。虽然我通常可以从数据中做出有根据的猜测,但我无法在论文中做出这样的猜测。
  • tb 参数确实为测试集发生了变化(参见上面的编辑)。如果您使用合理的起始值,我不知道为什么优化器会卡住。我使用dnorm(),因为mle2 不做最小二乘,它做一般最大似然估计,而dnorm() 是一种使其与最小二乘拟合等效的方法。
  • 使用lm 为指定断点拟合分段线性模型,然后进行一维非线性优化 (optimize) 以选择断点会更有效和更稳健。或者使用strucchange 包。
猜你喜欢
  • 2016-02-02
  • 1970-01-01
  • 2018-06-04
  • 2011-01-15
  • 2017-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多