每年(或许是从11月份开始,或许是从9月份开始),企业中层管理人员都要忙于做预算了。
预算的重中之重,自然是销售预算。
尽管理论上有零基预算、弹性预算等等,但是在实际操作上,恐怕使用最多的方法还是“拍脑袋预算”!
什么是“拍脑袋预算”呢?
就是高层简单粗暴地要求:明年的销售收入预算,要比今年增长40%、60%,或者80%......
从前一位集团董事长和下属公司总经理编制年度预算,董事长因势利导引诱总经理多次拔高销售预测...结果,年终将近,预算没有实现,董事长责怪总经理没有完成预算,总经理委屈地说:“当初我们就没有定那么高的预算,是您一再要求我们,说是即便达不到,但是目标还是可以放高远一点的嘛......”
这不是一个笑话!特别是绩效考核与预算实现程度挂钩的情况下,这事儿更加纠结......
这年头和钱有关的还有什么事情是确定的呢?政策、市场、跨界打劫者、双边多边关系...瞬息万变,预算到底应该定到多高,谁能知道呢?
如果有一种大家都认可的方法,可以自动计算出预算值,那就好了!
100%完全自动化是不可能的,也不符合直觉。
但是,可以转移争议的焦点,从争论预算值是高了还是低了?,转移为应该更加关注过去,还是关注现在。
或者也可以说,是当前期间数据对预测值的影响更大,还是前期历史数据对预测值的影响更大?
这个焦点,就是 $\alpha$ 值的确定。
- 当时间序列呈现较稳定的水平趋势时,应选较小的 $\alpha$ ,一般可在0.05~0.20之间取值
- 当时间序列有波动,但长期趋势变化不大时,可选稍大的 $\alpha$ 值,常在0.1~0.4之间取值
- 当时间序列波动很大,长期趋势变化幅度较大,呈现明显且迅速的上升或下降趋势时,宜选择较大的 $\alpha$ 值,如可在0.6~0.8间选值,以使预测模型灵敏度高些,能迅速跟上数据的变化
- 当时间序列数据是上升(或下降)的发展趋势类型,$\alpha$ 应取较大的值,在0.6~1之间
时间序列就是按时间顺序排列的,随时间变化的数据序列。譬如我们熟知的GDP,CPI、销售额,顾客数,访问量...
随机过程的特征包括均值、方差、协方差等。如果随机过程的特征随着时间变化,则称此过程是非平稳的;如果随机过程的特征不随时间而变化,就称此过程是平稳的。
非平稳时间序列分析时,如果导致非平稳的原因是确定的,可以用的方法主要有趋势拟合模型、季节调整模型、移动平均、指数平滑等方法。如果导致非平稳的原因是随机的,方法主要有ARIMA(autoregressive integrated moving average)及自回归条件异方差模型等。
$$\overline{X} = \frac{\sum_{i=1}^n X_i}{n}$$
方差用于描述随机变量对于数学期望的偏离程度,等于各个数据与其算术平均数的离差平方和的平均数,分离散型和连续型两种,称为标准差或均方差。
标准差:$$s = \sqrt{ \frac{\sum_{i=1}^n (X_i-\overline{X})^2}{n-1} }$$
方差:$$s^2 = \frac{\sum_{i=1}^n (X_i-\overline{X})^2}{n-1}$$
标准差和方差描述的是一维数据,而协方差是用来度量两个随机变量关系的统计量。大于两个随机变量的就是协方差矩阵。
协方差统计结果的意义
如果结果为正值,说明两者是正相关的
如果结果为负值,说明两者是负相关的
* 如果结果为0,说明两者不线性相关
$$cov(X,Y)=\frac{\sum_{i=1}^n (X_i-\overline{X})(Y_i-\overline{Y})}{n-1}$$
一方面,导致非平稳的原因,于汇市、股市而言是不确定的,因为很难有一股决定性力量可以左右大势(A股或许除外),而企业销售额,固然市场千变万化,但是一般情况下主要还是可以由产品特性、市场营销等手段来主导。所以,导致非平稳的原因,于企业销售额而言是基本可确定的。
另一方面,趋势拟合只是对不具有线性关系的离散点拟合出一条逼近直线、简单移动平均因为缺乏权数调整而与现实不符、季节性调整在月份预测中有效,但年度预测无效。或许经济周期可以是一个考虑因素,但对于仅仅预测一年或者两年,则经济周期的影响非常有限。
综上所述,指数平滑方法对于企业销售是一种最有效的方法。
已知数据:从1997年到2016年,每年的销售额如下图所示:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import statsmodels.api as sm
annual= ['2016','2015','2014','2013','2012','2011','2010','2009','2008','2007','2006','2005','2004','2003','2002','2001','2000','1999','1998','1997']
incoming=[12.95,12.07,12.37,12.08,12.10,11.93,11.90,11.95,12.14,12.10,12.09,12.40,12.29,12.41,12.86,13.38,14.03,14.64,15.64,16.57]
annual.reverse()
incoming.reverse()
time_series = pd.Series(incoming)
time_series.index = pd.Index(sm.tsa.datetools.dates_from_range('1997','2016'))
time_series.plot(figsize=(12,6))
plt.show()
def exSm(a):
se=[]
for i in range(len(annual)):
pre=0.
if not i == 0:
pre = a * incoming[i]+(1-a)*se[i-1]
else:
pre = a*incoming[i] + (1-a)*(incoming[0]+incoming[1]+incoming[2])/3
se.append(round(pre,2))
predict=a*incoming[-1]+(1-a)*se[-1]
newyear=['2017']
annual_pre=annual+newyear
i=[]
i.append(incoming[-1])
incom_pre=incoming+i
se.append(predict)
x = annual_pre
y1= incom_pre
y2= se
xmark=[annual[-1],annual[-1]]
ymark=[min(se),max(se)]
fig = plt.figure(figsize=(12,6))
l1, = plt.plot(x, y1, 'r--', label="imcoming", marker ='o')
l2, = plt.plot(x, y2, 'g-', label="$ES^{(1)}$", marker ='o')
l3, = plt.plot(xmark, ymark, 'b-')
plt.legend(handles=[l1, l2], loc = 0, frameon=False, fontsize=16)
plt.grid(True)
plt.show()
exSm(0.2)
exSm(0.5)
exSm(0.8)
因为一次指数平滑法不适用于呈斜坡型线性变动的历史数据,所以我们选择使用二次指数平滑法。
def exSm(a):
se=[]
for i in range(len(annual)):
pre=0.
if not i == 0:
pre = a * incoming[i]+(1-a)*se[i-1]
else:
pre = a*incoming[i] + (1-a)*(incoming[0]+incoming[1]+incoming[2])/3
se.append(round(pre,2))
pred=a*incoming[-1]+(1-a)*se[-1]
se2=[]
se2.append(se[0])
for j in range(1, len(annual)):
pre2=a * se[j] + (1-a) * se2[j-1]
se2.append(round(pre2,2))
at = 2*se[-1]-se2[-1]
bt = a/(1-a) * (se[-1]-se2[-1])
Y_next = round((at+bt*1),2)
Y_next_next = round((at+bt*2),2)
newyear=['2017','2018']
annual_pre=annual+newyear
i=[]
i.append(incoming[-1])
i.append(incoming[-1])
incom_pre=incoming+i
se.append(pred)
se.append(pred)
se2.append(Y_next)
se2.append(Y_next_next)
x = annual_pre
y1= incom_pre
y2= se
y3=se2
xmark=[annual[-1],annual[-1]]
ymark=[min(se2)*0.95,max(se2)]
fig = plt.figure(figsize=(12,6))
l1, = plt.plot(x, y1, 'r--', label="imcoming", marker ='o')
l2, = plt.plot(x, y2, 'g--', label="$ES^{(1)}$", marker ='o')
l3, = plt.plot(x, y3, 'k-', label="$ES^{(2)}$", marker ='o')
l4, = plt.plot(xmark, ymark, 'b-')
plt.legend(handles=[l1, l2, l3], loc = 0, frameon=False, fontsize=16)
plt.grid(True)
plt.show()
mm=pd.DataFrame(x,columns=['x'])
mm=pd.concat([mm,pd.DataFrame(y1,columns=['y1'])],axis=1)
mm=pd.concat([mm,pd.DataFrame(y2,columns=['y2'])],axis=1)
mm=pd.concat([mm,pd.DataFrame(y3,columns=['y3'])],axis=1)
print(mm)
exSm(0.3)
exSm(0.5)
exSm(0.7)
$$\gamma_{t+1}^*=\alpha \gamma_{t}+(1-\alpha)\gamma_t^*$$
其中:
| 符号 | 含义 |
|---|---|
| $\gamma_{t+1}^*$ | t+1 期的预测值(或称本期 ( t 期)的平滑值 $S_t$) |
| $\gamma_t$ | t 期的实际值 |
| $\gamma_t^*$ | t 期的预测值,即上期的平滑值 $S_{t-1}$ |
利用滞后偏差的规律找出曲线的发展方向和发展趋势,然后建立直线趋势预测模型,故称为二次指数平滑法。
$$S_t^{(2)}=\alpha S_t^{(1)}+(1-\alpha)S_{t-1}^{(2)}$$
其中:
| 符号 | 含义 |
|---|---|
| $S_t^{(2)}$ | 第 t 周期的二次指数平滑值 |
| $S_t^{(1)}$ | 第 t 周期的一次指数平滑值 |
| $S_{t-1}^{(2)}$ | 第 t-1 周期的二次指数平滑值 |
| $\alpha$ | 加权系数(也称为平滑系数) |
二次平滑指数不能单独地进行预测,必须与一次指数平滑法配合,建立预测的数学模型,然后运用数学模型确定预测值。
$$\hat{Y}_{t+T}=a_t + b_t\bullet T$$
其中:
| 符号 | 含义 |
|---|---|
| $\hat{Y}_{t+T}$ | t+T 的预测值 |
| $T$ | t 期到预测期的间隔期数 |
| $a_t , b_t$ | 参数 |
其中参数$a_t$和$b_t$的计算公式为:
\begin{equation}
\left\{
\begin{array}{lr}
a_t=2S_t^{(1)}-S_t^{(2)} & \\
b_t=\dfrac{\alpha}{1-\alpha}(S_t^{(1)}-S_t^{(2)}) & \\
\end{array}
\right.
\end{equation}
其中$S_t^{(1)}$和$S_t^{(2)}$分别为一次和二次指数平滑值,其计算公式为: $$S_t^{(1)}=\alpha x_t^{(1)}+(1-\alpha)S_{t-1}^{(1)}$$
$$S_t^{(2)}=\alpha S_t^{(1)}+(1-\alpha)S_{t-1}^{(2)}$$
参考文章《推导指数平滑法预测模型的参数计算公式》.