#加载数据
x=read.table(file.choose())
#生成时间序列对象
xtimeseries
#画时间序列图
plot.ts(xtimeseries)
#增加线性拟合曲线
abline(lm(xtimeseries~time(xtimeseries)))
1、分解时间序列
分解一个时间序列意味着把它拆分成构成元件,一般序列包含一个趋势部分、一个不规则部分,如果是一个季节性时间序列,则还有一个季节性部分。
分解非季节性数据(趋势部分+不规则部分)
估计趋势部分:最常用的方法便是平滑法,比如计算时间序列的简单移动平均。为了更加准确地估计这个趋势部分,我们也许应该尝试下更大的跨度进行平滑。
在R的“TTR”包中的SMA()函数可以用简单的移动平均来平滑时间序列数据
# 使用SMA()函数时,你需要通过参数“n”指定来简单移动平均的跨度
#这仅仅是一个代码例子,该时间序列是有季节变化的
library(TTR)
xtimeseriesSMA
plot.ts(xtimeseriesSMA)
分解季节性数据(季节部分+趋势部分+不规则部分)
#对于可以使用相加模型进行描述的时间序列中的趋势部分和季节性部分,我们可以使用R中“decompose()”函数来估计。这个函数可以估计出时间序列中趋势的、季节性的和不规则的部分,而此时间序列须是可以用相加模型描述的。
xtimeseriescomponents
plot(xtimeseriescomponents)
#从原始时间序列中去除去季节部分。
xtimeseriesseasonallyadjusted
# 我们可以使用“plot()”画出季节性修正时间序列,代码如下:
plot(xtimeseriesseasonallyadjusted)
如果你有一个可用相加模型描述的,并且处于恒定水平和没有季节性变动的时间序列,你可以使用简单指数平滑法对其进行短期预测。
简单指数平滑法提供了一种方法估计当前时间点上的水平。为了准确的估计当前时间的水平,我们使用alpha参数来控制平滑。Alpha的取值在0到1之间。当alpha越接近0的时候,临近预测的观测值在预测中的权重就越小。
2、使用指数平滑法进行预测
指数平滑法可以用于时间序列数据的短期预测。
简单指数平滑法(非季节性变动和处于恒定水平、没明显趋势)
如果你有一个可用相加模型描述的,并且处于恒定水平和没有季节性变动的时间序列,你可以使用简单指数平滑法对其进行短期预测。
# 比如,使用简单指数平滑发对伦敦每年下雨量进行预测,HoltWinters()函数中设定参数beta=FALSE和gamma=FALSE,代码如下:
rainseriesforecasts
#预测的结果值
rainseriesforecasts$fitted
#样本内预测误差的误差平方之和
rainseriesforecasts$SSE
使用R中的“forecast”包中的“forecast.HoltWinters()”函数进行更远时间点上的预测。
library(forecast)
#h参数为预测之后的多少个时间窗口
rainseriescasts2
#绘画预测结果
plot.forecast(rainseriescasts2)
霍尔特指数平滑法(有明显趋势,非季节的相加模型)
如果你的时间序列可以被描述为一个增长或降低趋势的、没有季节性的相加模型,你可以使用霍尔特指数平滑法对其进行短期预测。
Holt指数平滑法估计当前时间点的水平和斜率。其平滑化是由两个参数控制的,alpha,用于估计当前时间点的水平,beta,用于估计当前时间点趋势部分的斜率。
正如简单指数平滑法一样,alpha和beta参数都介于0到1之间,并且当参数越接近0,大多数近期的观测则将占据预测更小的权重。
# 一个可能可以用相加模型描述的有趋势的、无季节性的时间序列案例就是这1866年到1911年每年女人们裙子的直径。这个数据可以从该文件获得(http://robjhyndman.com/tsdldata/roberts/skirts.dat)(初始数据来自Hipel and McLeod, 1994)
skirts
skirtsseries
plot.ts(skirtsseries)
# 例如,为了使用Holt指数平滑法修正一个裙边直径的预测模型,我们输入代码:
skirtsseriesforecasts
skirtsseriesforecasts
# 这里的alpha预测值为0.84,beta预测值为1.00。这都是非常高的值,告诉我们无论是水平上,还是趋势的斜率,当前值大部分都基于时间序列上最近的观测值。
#这样的直观感觉很好,因为其时间序列上的水平和斜率在整个时间段发生了巨大的变化。预测样本内误差的误差平方和是16954。
# 我们可以用黑色线条画出原始时间序列分布,用红色线条画出顶部的预测值,代码如下:
plot(skirtsseriesforecasts)
# 从该图我们可以看到样本内预测非常接近观测值,尽管他们对观测值来说有一点点延迟。
# 如果你想的话,你可以通过HoltWinters()函数中的“l.start”和“b.start”参数去指定水平和趋势的斜率的初始值。常见的设定水平初始值是让其等于时间序列的第一个值(在裙子数据中是608),而斜率的初始值则是其第二值减去第一个值(在裙子数据中是9)。
# 例如,为了使用Holt指数平滑法找到一个在裙边直径数据中合适的预测模型,我们设定其水平初始值为608,趋势部分的斜率初始值为9,代码如下:
HoltWinters(skirtsseries,gamma=FALSE,l.start = skirtsseries[1],b.start = skirtsseries[2]-skirtsseries[1])
## Holt-Winters exponential smoothing with trend and without seasonal component.
##
## Call:
## HoltWinters(x = skirtsseries, gamma = FALSE, l.start = skirtsseries[1], b.start = skirtsseries[2] - skirtsseries[1])
##
## Smoothing parameters:
## alpha: 0.8346775
## beta : 1
## gamma: FALSE
##
## Coefficients:
## [,1]
## a 529.278637
## b 5.670129
# 正如我们的简单指数平滑法一样,我们可以使用“forecast”包中的forecast.HoltWinters()函数预测未来时间而无需覆盖原始序列。
# 例如,我们的现在有的1866年到1911年的裙边直径时间序列数据,因此我们可以预测1912年到1930年(19个点或者更多),并且画出他们,代码如下:
skirtsseriescasts2
plot.forecast(skirtsseriescasts2)
Holt-Winters指数平滑法(增长或降低趋势、季节性变化、相加模型的时间序列)
如果你有一个增长或降低趋势并存在季节性可被描述成为相加模型的时间序列,你可以使用霍尔特-温特指数平滑法对其进行短期预测。
Holt-Winters指数平滑法估计当前时间点的水平,斜率和季节性部分。平滑化依靠三个参数来控制:alpha,beta和gamma,分别对应当前时间点上的水平,趋势部分的斜率和季节性部分。
参数alpha,beta和gamma的取值都在0和1之间,并且当其取值越接近0意味着对未来的预测值而言最近的观测值占据相对较小的权重。
#取对数可以减少极值带来的影响,消除方差不齐。
logxtimeseries
xtimeseriesforecasts
xtimeseriesforecasts
#用黑线画出原始数据的时间曲线图,用红线在上面画出预测值的时间曲线图:
plot(logxtimeseries)
plot(xtimeseriesforecasts)
#如果alpha相对较低,说明当前时间点估计得水平是基于最近观测和历史观测值。beta的估计值是0.00,表明估计出来的趋势部分的斜率在整个时间序列上是不变的,并且应该是等于其初始值。这是很直观的感觉,水平改变非常多,但是趋势部分的斜率b却仍然是大致相同的。与此相反的,gamma的值(0.96)则很高,表明当前时间点的季节性部分的估计仅仅基于最近的观测值。
# 我们可以从途中看出Holt-Winters指数平滑法是非常成功得预测了季节峰值,其峰值大约发生在每年的12月份。
# 为了预测非原始时间序列的未来一段时间,我们使用“forecast”包中的“forecast.HoltWinters()”函数。
# 例如,礼物消费原始数据是2013年7月到2016年8月。如果我们想预测2016年9月到2017年6月(12个月或者更多),并且画出预测,代码如下:
xtimeseriesforecasts2
plot.forecast(xtimeseriesforecasts2)
# 我们可以通过画相关图和进行Ljung-Box检验来检查样本内预测误差在延迟1-20阶时否是非零自相关的,并以此确定预测模型是否可以再被优化
acf(xtimeseriesforecasts2$residuals,lag.max=20)
Box.test(xtimeseriesforecasts2$residuals,lag=20,type="Ljung-Box")
# Box-Ljung test
#
$data: xtimeseriesforecasts2$residuals
#X-squared = 16.4789, df = 20, p-value = 0.6865
# 这个样本内预测误差的相关图并没有在延迟1-20阶内自相关系数超过置信界限的。而且,Ljung-Box检验的P值是0.68(>0.05),意味着是不足以证明延迟1-20阶是非零自相关的。
ps:自相关值超出95%的显著边界有可能是偶然的。
# 我们可以在整个时间段内检验预测误差是否是方差不变,并且服从零均值正态分布。方法是画出预测误差的时间曲线图和直方图(并覆盖上正太曲线):
plot.ts(xtimeseriesforecasts2$residuals) # make a time plot
plotForecastErrors(xtimeseriesforecasts2$residuals) # make a histogram
ARIMA模型(AR代表自回归,MA代表移动平均)
指数平滑法对于预测来说是非常有帮助的,而且它对时间序列上面连续的值之间相关性没有要求。但是,如果你想使用指数平滑法计算出预测区间,那么预测误差必须是不相关的,而且必须是服从零均值、方差不变的正态分布。
即使指数平滑法对时间序列连续数值之间相关性没有要求,在某种情况下,我们可以通过考虑数据之间的相关性来创建更好的预测模型。自回归移动平均模型(ARIMA)包含一个确定(explicit)的统计模型用于处理时间序列的不规则部分,它也允许不规则部分可以自相关。
时间序列的差分
ARIMA模型为平稳时间序列定义的。因此,如果你从一个非平稳的时间序列开始,首先你就需要做时间序列差分直到你得到一个平稳时间序列。如果你必须对时间序列做d阶差分才能得到一个平稳序列,那么你就使用ARIMA(p,d,q)模型,其中d是差分的阶数。
在R中你可以使用diff()函数作时间序列的差分。
# 我们可以通过键入下面的代码来得到时间序列(数据存于“xtimeseries”)的一阶差分,并画出差分序列的图:
xseriesdiff1
plot.ts(xseriesdiff1)
# 一阶差分时间序列结果(上图)的均值看起来平稳。因此,不需要再次做差分。如果不平稳继续做差分。
#xseriesdiff2
#plot.ts(xseriesdiff2)
例如:
install.packages("tseries")
library(tseries)
data(AirPassengers)
adf.test(diff(log(AirPassengers)), alternative="stationary", k=0)
Augmented Dickey-Fuller Test
data: diff(log(AirPassengers))
Dickey-Fuller = -9.6003, Lag order = 0, p-value = 0.01
alternative hypothesis: stationary
#如果是这样表示,这个序列是足够平稳做任何时间序列模型。
# 对于平稳性正式的检验称作“单位根测试”,可以在fUnitRoots包中得到
如果你的时间序列是平稳的,或者你通过做n次差分转化为一个平稳时间序列,接下来就是要选择合适的ARIMA模型,这意味着需要寻找ARIMA(p,d,q)中合适的p值和q值。(通过上面差分得出d=1)为了得到这些,通常需要检查平稳时间序列的(自)相关图和偏相关图。
我们使用R中的“acf()”和“pacf”函数来分别(自)相关图和偏相关图。在“acf()”和“pacf设定“plot=FALSE”来得到自相关和偏相关的真实值。
acf(xseriesdiff1,lag.max=20) #plot a correlogram
acf(xseriesdiff1,lag.max=20,plot=FALSE) # get the autocorrelation values
# 我们从上面相关图中可以看出在滞后1、6、12阶(lag1)的自相关值(-0.360)超出了置信边界。
# 要画出礼物消费在滞后1-20阶(lags 1-20)一阶差分时间序列的偏相关图,并得到偏相关的值,我们使用“pcf()”函数,输入:
pacf(xseriesdiff1,lag.max=20) #plot a partial correlogram
# 偏相关图显示在滞后1,2和5阶(lags 1,2,3)时的偏自相关系数超出了置信边界,为负值。
确定pq
首先判断acf图和pacf图是否平稳,加入假如非平稳那么需要差分,如果一阶差分后仍非平稳,则需要二阶差分,等等。在确定差分平稳后,需要判断p和q,
这里定阶方法有很多,因为p和q的确定也很复杂,不是一下子就可以确定的。主要有这么几种(1)观察法,直接观察,如果acf在q+1阶突然截断,在q处截尾,则为ma(q)序列,同理,pacf 在p处截尾则为ar(p)序列,否则为arma(p,q)序列,二者结合进一步判断
(2)参数检验,利用数理统计检验高阶模型的新增加的参数是否近似为零,检验模型残差的相关 特性等。
(3)信息准则,确定一个与模型阶数有关的准则,如AIC、BIC等,既考虑拟合效果接近程度, 又考虑参数个数。实际中往往多种方法综合应用,选择最合适的p,d,q.
ARMA(p,q)模型的ACF与PACF理论模式
模型 ACF PACF
AR(p) 衰减趋于零(几何型或振荡型) p阶后截尾(可以考虑邻项观测值上具有长期相关性)
MA(q) q阶后截尾 衰减趋于零(几何型或振荡型)(移动平均模型邻项观察值之间短期相关的特征)
ARMA(p,q) q阶后衰减趋于零(几何型或振荡型) p阶后衰减趋于零(几何型或振荡型)
auto.arima() 函数可以用来发现合适的ARIMA模型,例如输入 “library(forecast)”, 然后 “auto.arima(kings)”. 那么输出说明合适的模型是ARIMA(0,1,1).
既然对于英国国王去世年龄的时间序列,ARIMA(0,1)被认为是最合适的模型,那么原始的时间序列可以使用ARIMA(0,1,1) (p=0,d=1,q=1,这里d是差分阶层所需要的)来建模。
#auto.arima(logxtimeseries,ic='bic')如果你使用 “bic” 标准, 这里对参数个数要求非常严格, 使用简单的原则(p+q最小),模型在这里是同样优先的选择模型。
auto.arima(logxtimeseries,trace=T) #Best model: ARIMA(0,1,1)(0,1,1)[12]
xtimeseriesarima
你可以使用forecast.Arima() 中“level”参数来确定预测区间的置信水平。例如,为了得到99.5%的预测区间,我们输入: “forecast.Arima(xtimeseriesarima, h=5, level=c(99.5))”.
然后我们可以使用ARIMA模型来预测时间序列未来的值,使用R中forecast包的“forecast.Arima()” 函数。例如,为了预测接下来5个英国国王的去世年龄,我们输入:
library(forecast)
xtimeseriesforecasts
xtimeseriesforecasts
plot.forecast(xtimeseriesforecasts)
模型产生的预测误差检验:
过画相关图和进行Ljung-Box检验来检查样本内预测误差在延迟1-20阶时否是非零自相关
acf(xtimeseriesforecasts$residuals,lag.max=20)
Box.test(xtimeseriesforecasts$residuals,lag=20,type="Ljung-Box") # p=0.4835>0.05
#Ps: p值大,说明为纯随机序列。p值小,非纯随机序列,置信水平(1-p)
残差qq图,QQ图中的点的分布非常接近一条直线,只有在两段的时候有一些偏差,大部分数据分布很好。如果这样,该QQ图说明残差有很好的正态性。
qqnorm(xtimeseriesforecasts $residuals)
qqline(xtimeseriesforecasts $residuals)
# 相关图显示出在3阶接近显著(置信)边界,1、4、9阶超出显著(置信)边界,而且Ljung-Box检验的p值为0.01389<0.05,说明残差没有很好的独立性,不符合模型参数检验的第二个条件。
# 为了调查预测误差是否是平均值为零且方差为常数的正态分布(服从零均值、方差不变的正态分布),我们可以做预测误差的时间曲线图和直方图(具有正态分布曲线):
plot.ts(xtimeseriesforecasts$residuals) # make time plot of forecast errors
plotForecastErrors(kingstimeseriesforecasts$residuals)
forecast.Arima(airarima1,h=5,level=c(99.5))
PS:参考