I'm trying to perform a non linear fit to some simple data (corn yield by year). It's straight forward enough to do it with lm in R, but some of the data would fit better if there was a curve allowed, something on the order of year^1.5 or so.
x <- c(1979L, 1980L, 1981L, 1982L, 1983L, 1984L, 1985L, 1986L, 1987L,
1988L, 1989L, 1990L, 1991L, 1992L, 1993L, 1994L, 1995L, 1996L,
1997L, 1998L, 1999L, 2000L, 2001L, 2002L, 2003L, 2004L, 2005L,
2006L, 2007L, 2008L, 2009L, 2010L, 2011L, 2012L, 2013L, 2015L,
2016L, 2017L, 2018L, 2019L)
y <- c(47.3, 25.4, 39, 56.4, 41.4, 56.1, 60.3, 58, 64, 35, 56, 54,
37, 80, 59, 88, 55, 87, 90, 99, 93, 90.4, 80.7, 35, 80.2, 104.9,
59.9, 43.5, 97.9, 106, 132, 121.7, 120.1, 63.9, 142.5, 129.9,
114.8, 122.1, 164.3, 133.9)
yield_model <- nls(y ~ x^a,start=list(a = 1))
plot(x,y)
lines(x,predict(yield_model),lty=2,col="red",lwd=3)
> yield_model2
Nonlinear regression model
model: y ~ x^a
data: parent.frame()
a
0.5778
residual sum-of-squares: 46984
Number of iterations to convergence: 8
Achieved convergence tolerance: 7.566e-09
Why does the nls fit so poorly (visible if you plot it)? Did I do something wrong? You can imagine that a slight curve in a fit to the data would be better, along with a trend. It's like nls removed the trend or something. Any help would be great.
Two options. As mentioned by @RuiBarradas the issue is the specification of the model. You can set your starting values using a lm()
like this:
#Define initial values
mod <- lm(y~x)
#nls model
yield_model <- nls(y ~ a+x^b,
start=list(a = mod$coefficients[1],b=mod$coefficients[2]))
#Plot
plot(x,y)
lines(x,predict(yield_model),lty=2,col="red",lwd=3)
Output:
Or trying another approach like loess
:
library(ggplot2)
#Data
df <- data.frame(x=x,y=y)
#Plot
ggplot(df,aes(x=x,y=y))+
geom_point()+
stat_smooth(se=F)
Output: