Is a Google Sheets fit model a valid place to retrieve starting parameters for nls()?

Viewed 151

I am trying to fit an exponential model of form y = a*e^(x*b) in R to the data I have ran below, using the nls() function. I have read here and in other places that I need to feed the model reasonable parameters for a and b, but the way about getting those starting parameters seems very variable, and many of the suggested ways were methods that I could not find elaborations on. One suggestion said that you could copy your data into an Excel spreasheet, fit your model on the graph, and adjust the parameters until it appeared to fit the data reasonably well. Well, I went into Google Sheets, I inserted a chart based on the data below, and then selected Customize > Series > Trendline (exponential), and it fed me a formula of 5.51e^0.015x . Are these valid values I could use as my starting parameters? Does Google Sheets produce those effectively, or do I need to do the tinkering method, or try something else? I have read over and over again the importance of choosing proper starting values, so any help on this would be much appreciated. My educational background did not cover non linear models.

x       y
19.005  5.49
18.19   6
19.59   5.885
19.93   8.96
17.615  13.85
18.795  2.72
19.11   8.09
19.885  8.11
15.76   6.66
16.48   6.27
15.805  5.375
15.825  3.06
15.985  7.795
15.755  6.255
15.485  5.925
15.475  9.925
16.45   6.055
16.285  5.24
15.92   11.15
16.775  5.57
16.075  3.275
16.475  5.635
16.825  4.72
16.28   2.035
17.26   6.07
17.245  4.9
17.98   8.06
17.35   6.94
18.22   7.8
16.27   12.2
17.555  7.335
16.98   5.76
17.415  7.51
17.5    6.18
2 Answers

In the case of the data shown in the question we could just use a starting value of b = 1. If we use the plinear algorithm of nls then no starting value is needed for the linear parameter, a. In that case a should not be specified in the formula as it is implied already. It will be reported as .lin in the output. In the first line of code we sort DF giving DFs to facilitate later plotting.

DFs <- DF[order(DF$x), ]
fo <- y ~ exp(b * x)
fm <- nls(fo, DFs, start = list(b = 1), algorithm = "plinear")

However, if nls does not work with some other data then since y is strictly positive we can take logs of both sides to get a linear model fm0 which can be fit with lm to get a starting value for b. Use the plinear algorithm as above to avoid having to specify a starting value for a. DFs and fo are from above.

fm0 <- lm(log(y) ~ x, DFs)
fm2 <- nls(fo, DFs, start = list(b = coef(fm0)[[2]]), algorithm = "plinear")
fm2

## Nonlinear regression model
##   model: y ~ exp(b * x)
##    data: DFs
##       b    .lin 
## 0.02819 4.10908 
##  residual sum-of-squares: 205.6
##
## Number of iterations to convergence: 3 
## Achieved convergence tolerance: 2.073e-06

plot(y ~ x, DFs)
lines(fitted(fm2) ~ x, DFs, col = "red")

screenshot

Note

The input in reproducible form:

Lines <- "x       y
19.005  5.49
18.19   6
19.59   5.885
19.93   8.96
17.615  13.85
18.795  2.72
19.11   8.09
19.885  8.11
15.76   6.66
16.48   6.27
15.805  5.375
15.825  3.06
15.985  7.795
15.755  6.255
15.485  5.925
15.475  9.925
16.45   6.055
16.285  5.24
15.92   11.15
16.775  5.57
16.075  3.275
16.475  5.635
16.825  4.72
16.28   2.035
17.26   6.07
17.245  4.9
17.98   8.06
17.35   6.94
18.22   7.8
16.27   12.2
17.555  7.335
16.98   5.76
17.415  7.51
17.5    6.18"
DF <- read.table(text = Lines, header = TRUE)

I composed a similar answer to @G.Grothendieck's ... the general point is that you could use Google sheets, or Excel, or some other tool, to get starting values for nls(), but there's no need to.

I loaded your data using dd <- read.table(header=TRUE, text="x y\n19.005 5.49 ...")

fit log-linear model

m1 <- lm(log(y)~x,data=dd)
cc <- coef(m1)
## (Intercept)           x 
##   1.1404581   0.0399405 

The log-linear model doesn't actually give quite the same answer as nls() (although plenty good enough for starting values), because it makes different implicit assumptions about the error distribution (log-linear assumes that variance is constant on the log scale, while non-linear fits assume that variance is constant on the original scale, unless you specify otherwise).

log-link GLM

Another useful alternative is a generalized linear model fit with a Gaussian response and a log link. This actually fits exactly the same model as nls()

m2 <- glm(y~x, family=gaussian(link="log"), data=dd)
cc2 <- coef(m2)
## (Intercept)           x 
##  1.41320439  0.02819136 

... which you can see if you compare these coefficient values to the ones that nls() finds ...

s <- list(a=exp(cc2[[1]]), b= cc2[[2]])
m3 <- nls(y~a*exp(b*x), data=dd, start=s)
coef(m3)

enter image description here

Some different ways to make predictions and visualize them ...

par(las=1,bty="l")
plot(y~x,data=dd)
lines(dd$x,exp(predict(m1)))
lines(dd$x,exp(cc[1])*exp(cc[2]*dd$x), col=2,lty=2)

lines(dd$x, predict(m2,type="response"), col=3)
lines(dd$x, exp(cc2[1])*exp(cc2[2]*dd$x), col=4,lty=2)
legend("topright",col=1:4,lty=rep(1:2,2),
       c("lm(log) predict","lm(log) formula","glm predict","glm formula"))
dev.off()
Related