The basic problem is that you have not specified an independent variable. By specifying start(...)
for a, b, tc, and t
, you are telling nls(...)
that these are all parameters of the model.
It looks like you are using a simplified version of the LPPL model, in which a, b, and tc
are parameters, and t
is the independent variable. It looks like data2$Date
contains the time variable. You need to make sure the data2$Date
is of class POSIXct. So you could write:
df$Date <- as.POSIXct(df$Date, format="%m/%d/%y")
nls1 <- nls(Y~a+b*log(tc-Date), data=data2, start=list(a=0, b=1, tc=1466))
EDIT: In response to OP's comments
This is a great question, because it illustrates several issues in using nls(...)
. The problem you are having (now that the model is specified correctly) is that nls(...)
is not converging - a distressingly common occurrence. Basically, unless your starting parameter estimates are relatively close to the final, fitted values (or unless the model is extremely "well behaved"), nls will fail. [Note also that the paper you cite mentions that b is restricted to b < 0, whereas you are starting with b=1.] So what to do?
The minpack.lm(...)
function in package minpack
uses the exceptionally robust Levenberg-Marquardt algorithm for non-linear least squares estimation. In fact, the paper you cite mentions L-M specifically. The problem with minpack.lm(...)
is that it is much more difficult to use (you have to define a function which returns the residuals at a given step, rather than just defining the function to fit). Plus, minpack.lm(...)
does not calculate statistics of the fit.
So the solution is to use them both! Use minpack.lm(...)
to estimate the parameters, then use those as "starting values" in nls(...)
. The code below does that. Having a model fitted using nls(...)
will make it much easier to generate statistics of the fit, predicted values, residuals, and also to apply the model to new datasets.
# this section just grabs the DJIA for 1982 - 1987; you already have this
library(tseries)
library(zoo)
ts <- get.hist.quote(instrument="DJIA",
start="1982-01-01", end="1987-08-01",
quote="Close", provider="yahoo", origin="1970-01-01",
compression="d", retclass="zoo")
df <- data.frame(ts)
df <- data.frame(Date=as.Date(rownames(df)),Y=df$Close)
df <- df[!is.na(df$Y),]
# end of setup...
library(minpack.lm) # for nls.lm(...)
library(ggplot2) # for ggplot
df$days <- as.numeric(df$Date - df[1,]$Date)
# model based on a list of parameters
f <- function(pars, xx) {pars$a + pars$b*log(pars$tc - xx)}
# residual function
resids <- function(p, observed, xx) {df$Y - f(p,xx)}
# fit using Levenberg-Marquardt algorithm
nls.out <- nls.lm(par=list(a=1,b=-1,tc=5000), fn = resids,
observed = df$Y, xx = df$days)
# use output of L-M algorithm as starting estimates in nls(...)
par <- nls.out$par
nls.final <- nls(Y~a+b*log(tc-days),data=df,
start=c(a=par$a, b=par$b, tc=par$tc))
summary(nls.final) # display statistics of the fit
# append fitted values to df
df$pred <- predict(nls.final)
# plot the results
ggplot(df)+
geom_line(aes(x=Date,y=Y),color="black")+
geom_line(aes(x=Date,y=pred),color="blue",linetype=2)+
labs(title="LPPL Model Applied to DJIA (1982 - 1987)",
x="", y="DJIA (daily close)")+
theme(plot.title=element_text(face="bold"))
