---
title: "Holt两参数指数平滑模型"
author: "Rui"
date: "2023-06-01"
categories: [R]
image: "goldencoast.jpg"
format:
html:
code-fold: true
code-tools: true
---
```{=html}
<iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width=330 height=86 src="//music.163.com/outchain/player?type=2&id=1496089152&auto=1&height=66"></iframe>
```
```{r setup, include = FALSE}
# 设置默认参数
knitr::opts_chunk$set(
echo = TRUE,
fig.align = "center",
message = FALSE,
warning = FALSE,
collapse = TRUE
)
```
![](goldencoast.jpg)
# 模型介绍
Holt 两参数指数平滑适用于对含有线性趋势的序列进行修匀。他的基本思想是假定序列有一个比较固定的线性趋势——每期都递增或递减 $r$,那么第 $t$ 期的估计值就应该等于第 $t-1$ 期的观察值加上每期固定的趋势变动值,即
$$
\hat{x}_{t} = x_{t-1} + r
$$
但是由于随机因素的影响,每期的递增或递减值不会恒定为 $r$,它会随着时间上下波动,所以趋势序列其实是一个随机序列 $\{r_{t}\}$,因而
$$
\hat{x}_{t} = x_{t-1} + r_{t-1}
$$
考虑用第t期的观察值和第 $t$ 期的估计值加权平均数作为第 $t$ 期的修匀值:
$$
\tilde{x}_{t}=\alpha x_{t}+(1-\alpha)\hat{x}_{t}
$$
$$
\Rightarrow \tilde{x}_{t}=\alpha x_{t}+(1-\alpha)(x_{t-1}+r_{t-1}), \quad 0< \alpha <1
$$
因为趋势序列 $\{r_{t}\}$ 也是一个随机序列,为了使修匀序列 $\tilde{x}$ 更平滑,我们对 $\{r_{t}\}$ 也进行一次修匀处理:
$$
r_{t}=\beta(\tilde{x}_{t}-\tilde{x}_{t-1})+(1-\beta)r_{t-1}, \quad 0<\beta<1
$$
这就是 Holt 两参数指数平滑的构造思想,它的平滑公式为:
$$
\left\{\begin{matrix}
\tilde{x}_{t}=\alpha x_{t}+(1-\alpha)(x_{t-1}+r_{t-1}) \\
r_{t}=\beta(\tilde{x}_{t}-\tilde{x}_{t-1})+(1-\beta)r_{t-1}
\end{matrix}\right.
$$
式中,$\alpha$,$\beta$ 为两个平滑系数,也称平滑参数,它们满足 $0<\alpha,\beta<1$。
此外,还需要确定两个序列的初始值:
1. 平滑序列的初始值 $\tilde{x}_{0}$。最简单的方法是指定 $\tilde{x}_{t}=x_{1}$;
2. 趋势序列的初始值 $r_{0}$。最简单的方法是指定一个区间长度n,用这段区间的平均趋势作为趋势初始值:
$$
r_{0}=\frac{x_{n+1}-x_{1}}{n}
$$
假定最后一期的修匀值为 $\tilde{x}_{T}$,那么使用 Holt 两参数指数平滑方法,向前 $l$ 期的预测值为:$\tilde{x}_{T}(l)=\tilde{x}_{T} + l \cdot r_{T}$。
# 例子 安徽省老年人口预测
> 数据:1990-2020年安徽省老年人口数<br>
来源:[安徽统计年鉴](http://tjj.ah.gov.cn/ssah/qwfbjd/tjnj/index.html)
## 读取数据
```{r}
# 读取数据
data <- read.csv("data/安徽省老年人口数.csv")
x <- ts(data$老年人口数, start = 1990) # 转换为时间序列数据(本质是一个原子向量)
head(data)
```
## 画出时序图
```{r}
# 画出时序图
plot(
x,
pch = "*", type = "o", lwd = 2, col = "blue",
main = "", xlab = "时间(年)", ylab = "老年人口数(万人)"
)
```
## 模型拟合
```{r}
# 进行Holt两参数平滑
x_fit <- HoltWinters(x, gamma=FALSE)
x_fit # 查看拟合结果
x_fit$fitted # 查看拟合值
```
## 预测
```{r}
# 预测
library(zoo)
library(forecast)
x_fore <- forecast(x_fit, h=4) # 4期预测
x_fore # 输出预测值,包含80%和95%的CI
plot(
x_fore,
pch = "*", type = "o", lwd = 2, col = "red",
main = "", xlab = "时间(年)", ylab = "老年人口数(万人)"
)
lines(x_fit$fitted[ , 1], lwd = 2, col = "blue") # 添加拟合线
legend(
"topleft",
c("老年人口实际值", "指数平滑拟合值"),
col = c("red", "blue"),
lwd = c(2, 2),
pch = c("*", ""),
bty = "n"
) # 设置图例
```
## 保存结果
```{r}
# 保存数据
write.csv(x_fit$fitted, "data/Holt-fit.csv") # 保存拟合结果
write.csv(x_fore, "data/Holt-forecast.csv") # 保存预测结果
print("Work done!")
```
## 残差白噪声检验
白噪声的三个性质:
* 零均值
一般不是很重要,因为即使均值为非零常数,也可以对时间序列数据中心化实现。
* 纯随机性
序列各项之间没有任何相关关系,序列在进行完全无序的随机波动。
* 方差齐性
序列的每个变量的方差都相等。若方差非齐性,则参数的显著性检验失去意义,模型拟合的精度会降低。
### 画出残差时序图
```{r}
res = x - x_fit$fitted[ , 1] # 求出残差
# 时序图检验
plot(
res,
type = "o", pch = 16, col = "blue", lwd = 1.5,
main = "", xlab = "时间(年)", ylab = "残差"
) # 残差时序图
abline(h = 0, lty = 2) # 辅助线
```
### 画出自相关图和偏自相关图
```{r}
par(mar = c(5, 5, 4, 3))
acf(res, lag = 30) # 自相关图
pacf(res, lag = 30) # 偏自相关图
```
ACF 与 PACF 均在两倍标准差范围内,说明残差序列平稳,且应该具有纯随机性。但从图标来判断序列是否是纯随机的具有一定的主观性,我们需要进行客观的统计检验。
### 统计检验
Barlett 证明:如果一个时间序列是纯随机的,得到一个 $n$ 期的观测序列 $\{x_t, t=1,2,\cdots,n\}$,那么该序列的延迟非零期的样本自相关系数将近似服从均值为零,方差为序列观察期数倒数的正态分布,即:
$$
\hat{\rho_k}\sim N(0,\frac{1}{n}),\quad \forall k \neq 0
$$
于是,可以构造以下统计检验量来检验序列的纯随机性。
$$
\begin{alignat*}{2}
& H_0: \rho_1 = \rho_2 = \cdots = \rho_m, \quad \forall m \geqslant 1 \\
& H_1: \exists \rho_k \neq 0, \quad \forall m\geqslant 1,k\leqslant m
\end{alignat*}
$$
1. Q 检验统计量
Box 和 Pierce 推导出了 $Q$ 统计量:
$$
Q=n \sum_{k=1}^{m} \hat{\rho_{k}}^{2} \sim \chi^2(m)
$$
式中 $n$ 为观测期数,$m$ 为指定滞后期数,$Q$ 统计量近似服从自由度为 $m$ 的卡方分布。
2. LB 统计量
$Q$ 统计量在大样本场合下检验效果较好,但在小样本场合不太精确。Box 和 Ljung 推导出了适用于小样本场合下的 $LB$ 统计量作为 $Q$ 统计量的修正:
$$
LB=n(n+2) \sum_{k=1}^{m} (\frac{\hat{\rho_{k}}^{2}}{n-k}) \sim \chi^2(m)
$$
```{r}
# 纯随机性检验
Box.test(res, type = "Box-Pierce", lag = 20) # Q统计量
Box.test(res, type = "Ljung-Box", lag = 20) # LB统计量,更适用于小样本
# 多期滞后的随机性检验
for (i in 1:4) print(Box.test(res, type = "Ljung-Box", lag = 5*i))
```
$P$ 值均大于给定的显著性水平 $\alpha$,所以该序列不能拒绝纯随机性的原假设。但由残差时序图可以看出方差可能非齐,对于无自相关又异方差的序列,暂时没有较好的方法,故不做讨论。