基本问题是您没有指定自变量。通过指定start(...)
for a, b, tc, and t
,您是在告诉nls(...)
这些都是模型的所有参数。
看起来您正在使用 LPPL 模型的简化版本,其中a, b, and tc
是参数,并且t
是自变量。它看起来像data2$Date
包含时间变量。您需要确保data2$Date
是 POSIXct 类。所以你可以写:
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))
编辑:回应OP的评论
这是一个很好的问题,因为它说明了使用nls(...)
. 您遇到的问题(现在已经正确指定了模型)nls(...)
是没有收敛 - 一个令人痛苦的普遍现象。基本上,除非您的起始参数估计值相对接近最终的拟合值(或者除非模型非常“表现良好”),否则 nls 将失败。[还请注意,您引用的论文提到 b 限制为 b < 0,而您从 b = 1 开始。] 那该怎么办?
包中的minpack.lm(...)
函数minpack
使用异常稳健的 Levenberg-Marquardt 算法进行非线性最小二乘估计。事实上,你引用的论文特别提到了 LM。问题minpack.lm(...)
在于它更难使用(您必须定义一个在给定步骤返回残差的函数,而不仅仅是定义要拟合的函数)。另外,minpack.lm(...)
不计算拟合的统计数据。
所以解决方案是同时使用它们!用于minpack.lm(...)
估计参数,然后将其用作 中的“起始值” nls(...)
。下面的代码就是这样做的。使用拟合模型nls(...)
将使生成拟合、预测值、残差的统计数据以及将模型应用于新数据集变得更加容易。
# 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"))