使用二次平台模型解释 R 中的 nls 并进行故障排除

机器算法验证 r 解释 指数分布 曲线拟合 nls
2022-03-19 18:21:18

我正在尝试在一些比例数据上运行二次平台模型,其中值绑定在 0 到 100 之间。我需要一些帮助来解决我遇到的一些错误,并正确解释结果以及理解方程以及如何写出来正确。如果有人对这些模型有经验,任何帮助将不胜感激,因为我已经碰壁了。

示例数据:

Days    Type    Area 
0   Abrasion    0
11  Abrasion    65.6513749
13  Abrasion    79.1887936
15  Abrasion    88.3947998
26  Abrasion    98.2726653
38  Abrasion    100
0   Abrasion    0
70  Abrasion    93.5047459
124 Abrasion    100
0   Abrasion    0
7   Abrasion    78.2666991
8   Abrasion    78.3624009
9   Abrasion    78.9448106
14  Abrasion    81.6443138
24  Abrasion    97.9969096
29  Abrasion    98.8788699
50  Abrasion    99.4708654
53  Abrasion    100
0   Laceration  0
8   Laceration  8.05965381
22  Laceration  67.1254163
83  Laceration  100
0   Laceration  0
8   Laceration  59.1650901
69  Laceration  96.1942307
74  Laceration  100
0   Laceration  0
49  Laceration  82.5396751
133 Laceration  100
0   Laceration  0
125 Laceration  100
0   Laceration  0
16  Laceration  48.5178133

X = 天数 Y = 面积

我想为这些数据拟合一个二次高原模型。

我正在使用的代码:

###  Find reasonable initial values for parameters

fit.lm    = lm(Area ~ Days, data=healing)

a.ini     = fit.lm$coefficients[1]
b.ini     = fit.lm$coefficients[2]
clx.ini   = mean(healing$Area)


###  Define quadratic plateau function

quadplat = function(x, a, b, clx) {
  ifelse(x  < clx, a + b * x + (-0.5*b/clx) * x * x, 
         a + b * clx + (-0.5*b/clx) * clx * clx)}

###  Find best fit parameters


model = nls(Area ~ quadplat(Days, a, b, clx), 
            data = healing, 
            start = list(a   = a.ini, 
                         b   = b.ini, 
                         clx = clx.ini),
            trace = FALSE,
            nls.control(maxiter = 1000))

summary(model)

当我在某些数据上运行它时,它工作正常,但其他时候我收到以下错误:

Error in nls(Area ~ quadplat(Days, a, b, clx), data = healing,  : 
  singular gradient

我不确定为什么我用一些数据而不是其他数据得到这个。例如,当我运行Laceration子集时,模型运行良好。模型输出:

Formula: Area ~ quadplat(Days, a, b, clx)

Parameters:
    Estimate Std. Error t value Pr(>|t|)    
a     1.2304     3.8509   0.320    0.753    
b     3.0869     0.5595   5.518 2.54e-05 ***
clx  62.7697    11.0592   5.676 1.80e-05 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 11.86 on 19 degrees of freedom

Number of iterations to convergence: 8 
Achieved convergence tolerance: 3.234e-06

我将此解释为关键阈值,其中 Y 没有统计变化而 X 增加是 62.7697 天。这是正确的解释吗?

下图:

在此处输入图像描述

对我来说,这个情节看起来不错。但是,当我对子abrasion集运行相同的分析时,我得到了singular gradient错误。为什么会这样,是因为数据不合适吗?

请有 nls 知识的人通过准确解释这个二次模型在做什么以及为什么我可能会出错来帮助我。我不想“黑箱”这种分析,我认为我缺少关键的理解。另外,如果有人擅长解释公式,你能帮我把这段代码写成一个可读的公式吗?

function(x, a, b, clx) {
  ifelse(x  < clx, a + b * x + (-0.5*b/clx) * x * x, 
         a + b * clx + (-0.5*b/clx) * clx * clx)}

非常感谢有关此问题的任何信息或关于 nls 的良好资源的指导。我真的需要一些帮助,如果需要可以附上我的完整数据集。

2个回答

我们需要更好的起始值。拟合一个非高原模型,model0,并使用其中的参数来拟合给出模型的所有数据点,然后使用其中的 a 和 b 以及 clx 的值网格(由于其有问题的性质)给出 model.Ab 和模型.La。(请注意,它无法根据网格的某些起始值生成拟合,从而导致错误消息,但 nls2 将继续处理进一步的起始值,因此可以忽略这些错误。)

library(nls2)

# ensure data is sorted for plotting
o <- with(healing, order(Type, Days))
h <- healing[o, ]

# last argument specifies whether there is or is not a plateau
quadplat = function(x, a, b, clx, plat = TRUE) {
  if (plat) x <- pmin(x, clx)
  a + b * x + (-0.5*b/clx) * x * x
}

# fit no plateau model with all data
st <- c(a = 1, b = 1, clx = 1)
model0 <- nls(Area ~ quadplat(Days, a, b, clx, FALSE), h, start = st)

# fit all data model
model <- nls(Area ~ quadplat(Days, a, b, clx), h, start = coef(model0))
co <- coef(model)

我们现在可以使用上面在起始值中计算的值来拟合和绘制子集模型。

if (exists("model.Ab")) rm(model.Ab)
model.Ab <- nls2(Area ~ quadplat(Days, a, b, clx), h, subset = h$Type == "Abrasion",
  start = data.frame(a = co[[1]], b = co[[2]], clx = 0:140))

if (exists("model.La")) rm(model.La)
model.La <- nls2(Area ~ quadplat(Days, a, b, clx), h, subset = h$Type == "Laceration",
  start = data.frame(a = co[[1]], b = co[[2]], clx = 0:140))
  
cols <- c(Abrasion = "red", Laceration = "blue")
plot(Area ~ Days, h, col = cols[Type], pch = 20, cex = 1.5)
lines(fitted(model.Ab) ~ Days, subset(h, Type == "Abrasion"), 
  col = cols["Abrasion"])
lines(fitted(model.La) ~ Days, subset(h, Type == "Laceration"), 
  col = cols["Laceration"])

(图后续) 截屏

替代模型

如果可以考虑其他模型,则该模型只有两个参数,更容易拟合,尽管参数较少,但残差平方和也较低。

model.Ab2 <- nls(Area ~ a * (1 - exp(- b * Days)), h, 
   subset = Type == "Abrasion", start = c(a = 100, b = .1))
 
model.La2 <- nls(Area ~ a * (1 - exp(- b * Days)), h, 
   subset = Type == "Laceration", start = c(a = 100, b = .1))

# plot
cols <- c(Abrasion = "red", Laceration = "blue")
plot(Area ~ Days, h, col = cols[Type], pch = 20, cex = 1.5)
lines(fitted(model.Ab2) ~ Days, subset(h, Type == "Abrasion"), 
  col = cols["Abrasion"])
lines(fitted(model.La2) ~ Days, subset(h, Type == "Laceration"), 
  col = cols["Laceration"])

(图后续) 截屏

一参数模型

如果我们在上一节的 2 参数模型中固定 a = 100,我们会得到一个 1 参数模型,它在统计上与 2 参数模型没有区别。从方差分析中显示的大于 0.05 的 p 值可以看出这一点,这表明我们不能拒绝零假设,即 1 和 2 参数模型对两个子集中的每一个都同样地描述了数据。

model.Ab3 <- nls(Area ~ 100 * (1 - exp(- b * Days)), h, 
   subset = Type == "Abrasion", start = c(b = .1))
 
model.La3 <- nls(Area ~ 100 * (1 - exp(- b * Days)), h, 
   subset = Type == "Laceration", start = c(b = .1))

anova(model.Ab3, model.Ab2)

anova(model.La3, model.La2)

还要注意它达到 y = 95 的点,即接近高原,是-log(1 - 95/100)/b(基于反转模型方程)。分子大约是 3,所以它大约在 0 处达到 95 3/b

其他

如果m <- nls(...)thensummary(m)将给出系数和其他信息的标准误差。

另外,如果有人擅长解释公式,你能帮我把这段代码写成一个可读的公式吗?

function(x, a, b, clx) {
  ifelse(x  < clx, a + b * x + (-0.5*b/clx) * x * x, 
         a + b * clx + (-0.5*b/clx) * clx * clx)}

F(X,一个,b,XCl)={一个+bX+(-0.5bXCl)×X2,如果 X<XCl一个+bXCl+(-0.5bXCl)×XCl2,否则

这简化为:

F(X,一个,b,XCl)={一个+bX(1-X2XCl),如果 X<XCl一个+bXCl2,否则

我替换的地方XCl为了clx使其更具可读性。