7

我不明白为什么我不能对这些数据使用 nls 函数。我尝试了很多不同的起始值,但我总是遇到同样的错误。

这是我一直在做的事情:

expFct2 = function (x, a, b,c)
{
  a*(1-exp(-x/b)) + c  
}
vec_x <- c(77.87,87.76,68.6,66.29)
vec_y <- c(1,1,0.8,0.6)
dt <- data.frame(vec_x=vec_x,vec_y=vec_y)
ggplot(data = dt,aes(x = vec_x, y = vec_y)) +  geom_point() + 
     geom_smooth(data=dt, method="nls", formula=y~expFct2(x, a, b, c),
       se=F, start=list(a=1, b=75, c=-5)

我一直有这个错误:

Error in method(formula, data = data, weights = weight, ...) : 
  singular gradient
4

3 回答 3

9

这可以用两个线性参数 (.lin1.lin2) 和一个非线性参数 ( b) 来编写,如下所示:

a*(1-exp(-x/b)) + c  
= (a+c) - a * exp(-x/b)
= .lin1 + .lin2 * exp(-x/b)

where .lin1 = a+cand .lin2 = -a(so a = - .lin2and c = .lin1 + .lin2) 这让我们可以使用"plinear"它只需要指定单个非线性参数的起始值(消除如何为其他参数设置起始值的问题)并且尽管起始值b=75远离解决方案:

nls(y ~ cbind(1, exp(-x/b)), start = list(b = 75), alg = "plinear")

这是运行的结果,我们可以从问题的规模.lin2看出问题的规模严重不足:

> x <- c(77.87,87.76,68.6,66.29)
> y <- c(1,1,0.8,0.6)
> nls(y ~ cbind(1, exp(-x/b)), start = list(b = 75), alg = "plinear")
Nonlinear regression model
  model:  y ~ cbind(1, exp(-x/b)) 
   data:  parent.frame() 
         b      .lin1      .lin2 
 3.351e+00  1.006e+00 -1.589e+08 
 residual sum-of-squares: 7.909e-05

Number of iterations to convergence: 9 
Achieved convergence tolerance: 9.887e-07 
> R.version.string
[1] "R version 2.14.2 Patched (2012-02-29 r58660)"
> win.version()
[1] "Windows Vista (build 6002) Service Pack 2"

编辑:添加了示例运行和缩放评论。

于 2012-03-13T23:43:01.577 回答
9

在任何情况下,将三参数非线性模型拟合到四个数据点都将具有一定的挑战性,尽管在这种情况下数据表现良好。第 1 点是您的参数 (-5) 的起始值c已经偏离了。绘制与您的起始参数相对应的曲线图片(见下文)将帮助您理解这一点(因此将认识到您获得的曲线将从c最小值到c+a最大值,并且您的数据范围从 0.6 到1 ...)

然而,即使有一个更好的开始猜测,我发现自己对控制参数(即control=nls.control(maxiter=200))大惊小怪,然后是更多的警告——nls并不以其鲁棒性而闻名。所以我尝试了这个SSasympOff模型,它实现了你想要拟合的曲线的自启动版本。

start1 <- list(a=1, b=75, c=-5)
start2 <- list(a=0.5, b=75, c=0.5)  ## a better guess

pfun <- function(params) {
  data.frame(vec_x=60:90,
             vec_y=do.call(expFct2,c(list(x=60:90),params)))
}
library(ggplot2)
ggplot(data = dt,aes(x = vec_x, y = vec_y)) +  geom_point() +
  geom_line(data=pfun(start1))+
  geom_line(data=pfun(start2),colour="red")+
  geom_smooth(data=dt, method="nls", formula=y~SSasympOff(x, a, b, c),
              se=FALSE)

nls 一般来说,我的建议是,如果您适合geom_smooth并构建您想要添加的曲线,则更容易找出正在发生的事情并解决问题predict.nls......

更一般地说,获得良好起始参数的方法是了解您正在拟合的函数的几何形状,以及哪些参数控制曲线的哪些方面。正如我上面提到的,c是移位饱和指数曲线的最小值,a是范围,b是一个比例参数(你可以看到,当 时x=b,曲线是1-exp(-1)或大约是从最小值到最大值的 2/3 )。一点代数和微积分(即取极限),或者玩弄这个curve()函数,都是收集这些信息的好方法。

于 2012-03-13T23:16:14.443 回答
2

我很难找到对您的参数的解释:a 是斜率,b 是收敛速度,a+c 是极限,但 c 本身似乎没有多大意义。重新参数化您的功能后,问题就消失了。

f <- function (x, a,b,c) a + c * exp(-x/abs(b))
nls(y~f(x, a, b, c), data=dt, start=list(a=1, b=75, c=-5), trace=TRUE)

但是,c看起来的价值非常非常高:这可能是模型最初未能收敛的原因。

Nonlinear regression model
  model:  y ~ f(x, a, b, c) 
   data:  dt 
         a          b          c 
 1.006e+00  3.351e+00 -1.589e+08 
 residual sum-of-squares: 7.909e-05

Number of iterations to convergence: 9 
Achieved convergence tolerance: 2.232e-06 

这是同一函数的另一个更合理的参数化。

g <- function (x, a,b,c) a * (1-exp(-(x-c)/abs(b)))
nls(y~g(x, a, b, c), data=dt, start=list(a=1, b=75, c=-5), trace=TRUE)

Nonlinear regression model
  model:  y ~ g(x, a, b, c) 
   data:  dt 
     a      b      c 
 1.006  3.351 63.257 
 residual sum-of-squares: 7.909e-05

Number of iterations to convergence: 10 
Achieved convergence tolerance: 1.782e-06 
于 2012-03-13T23:41:04.027 回答