Wang Haihua
🍈 🍉🍊 🍋 🍌
一次移动平均实际上认为最近 $N$ 期数据对末来值影响相同, 都加权 $1 / N$, 而 $N$ 期以前的数据对末来值没有影响, 加权为 0。但是, 二次及更高 次移动平均的权数却不是 $1 / N$, 且次数越高, 权数的结构越复杂, 但永远保持对称的权数, 即两端项权数小, 中间项权数大, 不符合一般系统的动态性。
一般说来历史数据对末来值的影响是随时间间隔的增长而递减的。所以, 更切合实际的方法应是对各期观测值依时间顺序进行加权平均作为预测值。
指数平滑法可满足这一要求, 而且具有简单的递推形式。 指数平滑法根据平滑次数的不同, 又分为一次指数平滑法和二次指数平滑法等。指数平滑最适合用于简单的时间序列分析和中、短期预测。
设时间序列为 $y_{1}, y_{2}, \cdots, y_{t}, \cdots, \alpha$ 为加权系数, $0<\alpha<1$, 一次指数平滑 的预测公式为 $$ \hat{y}_{t+1}=S_{t}^{(1)}=\alpha y_{t}+(1-\alpha) S_{t-1}^{(1)}=S_{t-1}^{(1)}+\alpha\left(y_{t}-S_{t-1}^{(1)}\right), $$ 其中, $\hat{y}_{t+1}$ 表示第 $t+1$ 期预测值, $S_{t}^{(1)}, S_{t-1}^{(1)}$ 分别表示第 $t$ 期, $t-1$ 期一次指数平滑值。
为进一步理解指数平滑的实质, 把上式依次展开, 有 $S_{t}^{(1)}=\alpha y_{t}+(1-\alpha)\left[\alpha y_{t-1}+(1-\alpha) S_{t-2}^{(1)}\right]=\cdots=\alpha \sum_{j=0}^{\infty}(1-\alpha)^{j} y_{t-j}$, $S_{t}^{(1)}$ 是全部历史数据的加权平均, 加权系数分别为 $\alpha, \alpha(1-\alpha)$ $\alpha(1-\alpha)^{2}, \cdots$, 显然有
$$ \sum_{j=0}^{\infty} \alpha(1-\alpha)^{j}=\frac{\alpha}{1-(1-\alpha)}=1, $$由于加权系数符合指数规律, 又具有平滑数据的功能, 故称为指数平滑。
在进行指数平滑时, 加权系数的选择是很重要的。可以看出, $\alpha$ 的大小规定了在新预测值中新数据和原预测值所占的比重。 $\alpha$ 值越大, 新数据所占的比重就愈大, 原预测值所占的比重就愈小, 反之亦然。若把式子改写为 $$ \hat{y}_{t+1}=\hat{y}_{t}+\alpha\left(y_{t}-\hat{y}_{t}\right), $$ 则从式中可看出, 新预测值是根据预测误差对原预测值进行修正而得 到的。 $\alpha$ 的大小则体现了修正的幅度, $\alpha$ 值愈大, 修正幅度愈大; $\alpha$ 值愈小, 修正幅度也愈小。
若选取 $\alpha=\mathbf{0}$, 则 $\hat{y}_{t+1}=\hat{y}_{t}$, 即下期预测值就等于本期预测值, 在预测过程中不考虑任何新信息; 若选取 $\alpha=1$, 则 $\hat{y}_{t+1}=y_{t}$, 即下期预测值就等于本期观测值, 完全不相信过去的信息。
这两种极端情况很难做出正确的预测。 因此, $\alpha$ 值应根据时间序列的具体性质在 0~1 之间选择。具体如何选择一 般可遵循下列原则,
在实用上, 类似移动平均法, 多取儿个 $\alpha$ 值进行试算, 看哪个预测误差小,就采用哪个。
用一次指数平滑法进行预测, 除了选择合适的 $\alpha$ 外, 还要确定初始值 $S_{0}^{(1)}$ 初始值是由预测者估计或指定的。当时间序列的数据较多, 比如在 20 个以 上时, 初始值对以后的预测值影响很少, 可选用第一期数据为初始值。如果 时间序列的数据较少, 在 20 个以下时, 初始值对以后的预测值影响很大, 这时, 就必须认真研究如何正确确定初始值。一般以最初几期实际值的平均 值作为初始值。
某产品的11期价格如下表所示。试预测该产品第12期的价格。
时期 t | 价格 y_(t) | 预测值_(i)(alpha=0.2) | 预测值 i_(i)(alpha=0.5) | 预测值 i_(i)(alpha=0.8) |
---|---|---|---|---|
1 | 4.81 | 4.805 | 4.805 | 4.805 |
2 | 4.8 | 4.806 | 4.808 | 4.809 |
3 | 4.73 | 4.805 | 4.804 | 4.802 |
4 | 4.7 | 4.790 | 4.767 | 4.744 |
5 | 4.7 | 4.772 | 4.733 | 4.709 |
6 | 4.73 | 4.757 | 4.717 | 4.702 |
7 | 4.75 | 4.752 | 4.723 | 4.724 |
8 | 4.75 | 4.752 | 4.737 | 4.745 |
9 | 5.43 | 4.751 | 4.743 | 4.749 |
10 | 5.78 | 4.887 | 5.087 | 5.294 |
11 | 5.85 | 5.066 | 5.433 | 5.683 |
12 | 5.817 |
采用指数平滑法, 并分别取 $\alpha=0.2,0.5$ 和 $0.8$ 进行计算, 初始值 $$ S_{0}^{(1)}=\frac{y_{1}+y_{2}}{2}=4.805, $$ 即 $$ \hat{y}_{1}=S_{0}^{(1)}=4.805 . $$ 按预测模型 $$ \hat{y}_{t+1}=\alpha y_{t}+(1-\alpha) \hat{y}_{t} $$ 计算各期预测值, 列于表 中。
可以看出, $\alpha=\mathbf{0 . 2 , 0 . 5}$ 和 $0.8$ 时, 预测值是很不相同的。究竟 $\alpha$ 取何值为好, 可通过计算它们的预测标准误差 $S$, 选取使 $S$ 较小的那个 $\alpha$ 值。计算结果表明 $\alpha=0.8$ 时, $S$ 较小, 故选取 $\alpha=0.8$, 该产品第 12 期价格的预测值为 $\hat{y}_{12}=5.817$ 。
alpha | 0.2 | 0.5 | 0.8 |
---|---|---|---|
S | 0.4148 | 0.3216 | 0.2588 |
代码
import numpy as np
import pandas as pd
y=np.array([4.81,4.8,4.73,4.7,4.7,4.73,4.75,4.75,5.43,5.78,5.85])
def ExpMove(y,a):
n=len(y); M=np.zeros(n); M[0]=(y[0]+y[1])/2;
for i in range(1,len(y)):
M[i]=a*y[i-1]+(1-a)*M[i-1]
return M
yt1=ExpMove(y,0.2); yt2=ExpMove(y,0.5)
yt3=ExpMove(y,0.8);
s1=np.sqrt(((y-yt1)**2).mean())
s2=np.sqrt(((y-yt2)**2).mean())
s3=np.sqrt(((y-yt3)**2).mean())
d=pd.DataFrame(np.c_[yt1,yt2,yt3])
f=pd.ExcelWriter("data/pre2001.xlsx");
d.to_excel(f); f.close() #数据写入Excel文件,便于做表
print("预测的标准误差分别为:",s1,s2,s3) #输出预测的标准误差
yh=0.8*y[-1]+0.2*yt3[-1]
print("下一期的预测值为:",yh)
一次指数平滑法虽然克服了移动平均法的缺点。但当时间序列的变动 出现直线趋势时, 用一次指数平滑法进行预测, 仍存在明显的滞后偏差。因 此, 也必须加以修正。再作二次指数平滑, 利用滞后偏差的规律建立直线趋势模型, 这就是二次指数平滑法。其计算公式为
$$ \left\{\begin{array}{l} S_{t}^{(1)}=\alpha y_{t}+(1-\alpha) S_{t-1}^{(1)}, \\ S_{t}^{(2)}=\alpha S_{t}^{(1)}+(1-\alpha) S_{t-1}^{(2)}, \end{array}\right. $$式中 $S_{t}^{(1)}$ 为一次指数的平滑值; $S_{t}^{(2)}$ 为二次指数的平滑值。当时间序列 $\left\{y_{t}\right\}$, 从某时期开始具有直线趋势时, 可用直线趋势模型 $$ \begin{aligned} &\hat{y}_{t+m}=a_{t}+b_{t} m, \quad m=1,2, \cdots, \\ &\left\{\begin{array}{l} a_{t}=2 S_{t}^{(1)}-S_{t}^{(2)}, \\ b_{t}=\frac{\alpha}{1-\alpha}\left(S_{t}^{(1)}-S_{t}^{(2)}\right) \end{array}\right. \end{aligned} $$ 进行预测。 代入式子, 并令 $m=1$, 得 $$ \hat{y}_{t+1}=2 S_{t}^{(1)}-S_{t}^{(2)}+\frac{\alpha}{1-\alpha}\left(S_{t}^{(1)}-S_{t}^{(2)}\right) . $$
t | 钢产量 y_(t) | 一次平滑值 | 二次平滑值 | 预测值 hat(y)_(t) |
---|---|---|---|---|
1 | 2031 | 2031 | 2031 | |
2 | 2234 | 2091.9 | 2049.27 | 2031 |
3 | 2566 | 2234.13 | 2104.728 | 2152.8 |
4 | 2820 | 2409.891 | 2196.277 | 2418.99 |
5 | 3006 | 2588.724 | 2314.011 | 2715.054 |
6 | 3093 | 2740.007 | 2441.81 | 2981.171 |
7 | 3277 | 2901.105 | 2579.598 | 3166.002 |
8 | 3514 | 3084.973 | 2731.211 | 3360.4 |
9 | 3770 | 3290.481 | 2898.992 | 3590.348 |
10 | 4107 | 3535.437 | 3089.925 | 3849.752 |
11 | 4171.882 | |||
12 | 4362.815 |
取 $\alpha=0.3$, 初始值 $S_{0}^{(1)}$ 和 $S_{0}^{(2)}$ 都取序列的首项数值, 即 $S_{0}^{(1)}=S_{0}^{(2)}=2031$ 。 计算 $S_{t}^{(1)}, S_{t}^{(2)}$, 列于表 18.4。得到 $$ S_{10}^{(1)}=3535.437, \quad S_{10}^{(2)}=\mathbf{3 0 8 9 . 9 2 5} \text {. } $$ 由公式错误!末找到引用源。, 可得 $t=10$ 时 $$ a_{10}=2 S_{10}^{(1)}-S_{10}^{(2)}=3980.9484, \quad b_{10}=\frac{\alpha}{1-\alpha}\left(S_{10}^{(1)}-S_{10}^{(2)}\right)=190.9335 \text {, } $$ 于是, 得 $t=10$ 时直线趋势方程为 $$ \hat{\boldsymbol{y}}_{10+m}=3980.9484+190.9335 m, $$ 预测第 11、12 期的钢产量为 $$ \hat{y}_{11}=\hat{y}_{10+1}=4171.8819, \quad \hat{y}_{12}=\hat{y}_{10+2}=4362.8154 \text {. } $$
利用 $$ \hat{y}_{t+1}=2 S_{t}^{(1)}-S_{t}^{(2)}+\frac{\alpha}{1-\alpha}\left(S_{t}^{(1)}-S_{t}^{(2)}\right), \quad t=0,1, \cdots, 9 $$ 求已知各期的预测值。
import numpy as np
import pandas as pd
y=np.loadtxt('Pdata18_3.txt')
n=len(y); alpha=0.3; yh=np.zeros(n)
s1=np.zeros(n); s2=np.zeros(n)
s1[0]=y[0]; s2[0]=y[0]
for i in range(1,n):
s1[i]=alpha*y[i]+(1-alpha)*s1[i-1]
s2[i]=alpha*s1[i]+(1-alpha)*s2[i-1];
yh[i]=2*s1[i-1]-s2[i-1]+alpha/(1-alpha)*(s1[i-1]-s2[i-1])
at=2*s1[-1]-s2[-1]; bt=alpha/(1-alpha)*(s1[-1]-s2[-1])
m=np.array([1,2])
yh2=at+bt*m
print("预测值为:",yh2)
d=pd.DataFrame(np.c_[s1,s2,yh])
f=pd.ExcelWriter("pre2002.xlsx");
d.to_excel(f); f.close()
import numpy as np
import pandas as pd
y=np.array([4.81,4.8,4.73,4.7,4.7,4.73,4.75,4.75,5.43,5.78,5.85])
def ExpMove(y,a):
n=len(y); M=np.zeros(n); M[0]=(y[0]+y[1])/2;
for i in range(1,len(y)):
M[i]=a*y[i-1]+(1-a)*M[i-1]
return M
yt1=ExpMove(y,0.2); yt2=ExpMove(y,0.5)
yt3=ExpMove(y,0.8);
s1=np.sqrt(((y-yt1)**2).mean())
s2=np.sqrt(((y-yt2)**2).mean())
s3=np.sqrt(((y-yt3)**2).mean())
d=pd.DataFrame(np.c_[yt1,yt2,yt3])
f=pd.ExcelWriter("data/pre2001.xlsx");
d.to_excel(f); f.close() #数据写入Excel文件,便于做表
print("预测的标准误差分别为:",s1,s2,s3) #输出预测的标准误差
yh=0.8*y[-1]+0.2*yt3[-1]
print("下一期的预测值为:",yh)
预测的标准误差分别为: 0.4148362642161784 0.32164247683489516 0.25883473030674825 下一期的预测值为: 5.8165517935616
import numpy as np
import pandas as pd
y=np.loadtxt('data/steel.txt')
n=len(y); alpha=0.3; yh=np.zeros(n)
s1=np.zeros(n); s2=np.zeros(n)
s1[0]=y[0]; s2[0]=y[0]
for i in range(1,n):
s1[i]=alpha*y[i]+(1-alpha)*s1[i-1]
s2[i]=alpha*s1[i]+(1-alpha)*s2[i-1];
yh[i]=2*s1[i-1]-s2[i-1]+alpha/(1-alpha)*(s1[i-1]-s2[i-1])
at=2*s1[-1]-s2[-1]; bt=alpha/(1-alpha)*(s1[-1]-s2[-1])
m=np.array([1,2])
yh2=at+bt*m
print("预测值为:",yh2)
d=pd.DataFrame(np.c_[s1,s2,yh])
f=pd.ExcelWriter("data/pre2002.xlsx");
d.to_excel(f); f.close()
预测值为: [4171.88192538 4362.81543832]