Scoops
Scoops

Reputation: 61

Next Steps with nls()?

Working in R, I am trying to use nls() to fit some data to the following model:

y ~ c - a * exp(-b * x)

My data:

x <- c(8, 8, 10, 10, 10, 10, 12, 12, 12, 12, 14, 14, 14, 16, 16, 16, 18, 18, 20, 20, 20, 22, 22, 22, 24, 24, 24, 26, 26, 26, 28, 28, 30, 30, 30, 32, 32, 34, 36, 36, 38, 38, 40, 42)
y <- c(0.49, 0.49, 0.48, 0.47, 0.48, 0.47, 0.46, 0.46, 0.45, 0.43, 0.45, 0.43, 0.43, 0.44, 0.43, 0.43, 0.46, 0.45, 0.42, 0.42, 0.43, 0.41, 0.41, 0.40, 0.42, 0.40, 0.40, 0.41, 0.40, 0.41, 0.41, 0.40, 0.40, 0.40, 0.38, 0.41, 0.40, 0.40, 0.41, 0.38, 0.40, 0.40, 0.39, 0.39)


data <- data.frame(x, y)

Check to see if data fits the form of the model:

Plot of data

The book I'm working with says the coefficient estimates should be: c=0.3896, a=-0.2194, b=0.992.

My attempt using the given values, based on this thread 2, returns a singular gradient error:

m <- nls(y ~ I(c-a*exp(-b*x)), data=data, start=list(a=-.2194, b=1, c=0.3), trace=T)

I get acceptable values when I try to fit y ~ a * exp(-b * x) and y ~ exp(-b * x), but when I add the "c" term, I get the singular gradient error. I've also tried using nlsLM, which had the same issue, so I think it has to do with how I'm adding in that intercept term. Any advice is appreciated, thank you.

Upvotes: 3

Views: 99

Answers (1)

G. Grothendieck
G. Grothendieck

Reputation: 269586

Use the plinear algorithm in which case starting values are not needed for the parameters that enter linearly. In that case the right hand side should be a matrix such that each column multiplies one of the parameters that enters linearly.

fm <- nls(y ~ cbind(c = 1, a = -exp(-b*x)), data, 
  start = list(b = 1), alg = "plinear")
fm

giving:

Nonlinear regression model
  model: y ~ cbind(c = 1, a = -exp(-b * x))
   data: data
       b   .lin.c   .lin.a 
 0.09916  0.38963 -0.21940 
 residual sum-of-squares: 0.004997

Number of iterations to convergence: 6 
Achieved convergence tolerance: 3.075e-07

We can examine the fit visually:

plot(y ~ x, data)
lines(fitted(fm) ~ x, data, col = "red")

screenshot

Upvotes: 3

Related Questions