前言:2018年华为软赛初赛已经结束,很高兴我们团队取得西北赛区36强的成绩
。最近我会在博客上介绍我们使用过的预测方法,首先是指数平滑模型,指数平滑模型是简单高效的预测模型(分数高),我们主要使用的二次指数平滑和三次指数平滑,按7天进行数据加和,来预测短期数据。

    时间序列预测方法
的基本思想是:预测一个现象的未来变化时,用该现象的过去行为来预测未来。即通过时间序列的历史数据揭示现象随时间变化的规律,将这种规律延伸到未来,从而对该现象的未来作出预测。它的重要分支指数平滑法是由早期的移动平均法发展而来的。

    指数平滑预测法
是一种确定性的平滑预测法。其实质是:通过计算指数平滑平均数来平滑时间序列,消除历史统计序列中的随机波动,以找出其主要发展趋势。根据设置参数的不同可以分为
单指数预测、双指数预测和三指数预测
。其中,单指数具有一个参数,适合于具有平稳性特征时间序列的预测,也称为平稳性预测。双指数预测具有两个参数,适合于具有趋势性特征时间序列的预测,也称为趋势性预测。三指数预测具有三个参数,适合于具有趋势和季节性或周期性特征时间序列的预测,也称为季节性或周期性预测。指数平滑的三种预测方法中,预测曲线拟合程度的好坏与预测结果的准确度有关,而预测曲线的拟合程度与设定的参数值有直接关系。所以,参数的好坏非常重要。


   
指数平滑是当前产生平滑时间序列的一种比较流行的方法,也是画拟合曲线的一种方法,同时还可以对未来进行预测。指数平滑预测方法的基本思想是在预测下一周期的指标的同时,既考虑这个周期的指标,又不忘记前面的指标。在移动平均方法中,对每个数据赋予相同的权重,而指数平滑可以根据参数对数据赋予不同的权重,这样就可以获得更好的拟合曲线和预测结果。


    单指数模型

    单指数平滑具有一个平滑参数,适合对具有平稳特性的时间序列数据进行拟合和预测,其中数据的平稳特性是指数据的变化波动不大。


    (1)平滑公式

    用表示实际点的数据值,表示平滑点的数据值,对于序列中任一时刻点t,平滑值的平滑计算公式如式(1-1)所示:


        (1-1)


    (2)初始化


    单指数平滑的起始平滑点是,一般有两种方法进行初始化。一种方法是,另一种方法是取实际点的前四个或者前五个的平均值。


    (3)预测公式


    t+1序列时刻单指数平滑公式如式(1-2)所示:


        (1-2)


    t+i序列时刻单指数平滑公式如式(1-3)所示:


        (1-3)


式中i表示是经过的时刻点,也表示超前预测时刻。

    下面对平滑公式进行扩展,用基本的平滑公式代替,如式(1-4)所示:


        (1-4)


然后,接着替代,,如此递归,直到,这样就可以得到式(1-5),如下所示:

        (1-5)


    比如,当t=5时,如式(1-6)所示:


        (1-6)


    权重呈几何递减,所以较早数据的权重较小,所起的作用也就越小,这也是为什么将指数平滑方法称为指数平滑的原因所在。


    (4)二次指数平滑模型


   
在一次指数平滑预测公式中,无论是一步预测还是多步预测都使用同一公式,这对没有趋势的稳定序列是可行的。但是,若是用在上升或是下降趋势明显的需求序列上就不够理想。二次指数平滑就是为弥补这种缺陷而设计的一种方法,但它不是直接用于序列预测的方法,而是为计算有线性趋势的线性预测方程的系数服务的。


    所谓二次指数的平滑方法,是对一次指数平滑后的序列数据再作一次指数平滑,其平滑公式如下式(2-1)所示:


        (2-1)


式中,是二次指数平均值,为平滑常数。

    同一次指数平滑公式一样,在使用二次指数平滑公式时,也涉及初始值的取法。但随着时间的推移,初始值的影响是很小的。其取法与一次指数平滑的取法相似。


    由于时间序列具有线性趋势,故设线性预测方程如式(2-2)所示:


        (2-2)


式中称为预测时效,由指数平滑方法的基本定理有下式:

        (2-3)


    由此得到预测公式如式所示:

        (2-4)


   
数值实验证明,用二次指数平滑公式进行预测时,除序列的转折点外,其它点的预测精度都比一次指数平滑的预测精度高。此外,使用二次指数平滑进行预测会产生滞后误差的问题。

//二次指数平滑 int ExponentialSmoothing(double x[], int len, int pre_time) { double
weight = 0.912; double at = 0.0; double bt = 0.0; double* onetime_pre = (double
*)malloc(len * sizeof(double)); double* twotime_pre = (double *)malloc(len *
sizeof(double)); double *y=(double *)malloc(pre_time*sizeof(double));
memset(onetime_pre, 0, len * sizeof(double)); memset(twotime_pre, 0, len *
sizeof(double)); memset(y,0,pre_time*sizeof(double)); //一次指数平滑 onetime_pre[0] =
x[0]; //init for (int i = 1; i < len; i++) { onetime_pre[i] = weight * x[i] +
(1 - weight) * onetime_pre[i - 1]; } //二次指数平滑 twotime_pre[0] = (onetime_pre[0]
+ onetime_pre[1] + onetime_pre[2]) / 3; //init for (int i = 1; i < len; i++) {
twotime_pre[i] = weight * onetime_pre[i] + (1 - weight) * twotime_pre[i - 1]; }
//计算截距和斜率 at = 2 * onetime_pre[len -1] - twotime_pre[len - 1]; bt = weight / (1
- weight) * (onetime_pre[len - 1] - twotime_pre[len - 1]); //printf("at =
%f\n", at); //printf("bt = %f\n", bt); for (int T = 0; T < pre_time; T++) {
y[T] = at + bt * (T + 1); } double result=sumAllVectord(y,pre_time);
if(result<0) result=0; free(onetime_pre); free(twotime_pre); free(y); return
floor(result); }

    (5)三次指数平滑模型


   
当观察值分布出现曲率时,一般情况下二次指数平滑不再适用,要用三次指数平滑法,即非线性预测模型。三次指数平滑是将二次指数平滑值再进行一次系数平滑,如式(3-1)所示:


        (3-1)


    三次指数平滑非线性模型预测公式如式(3-2)所示:


        (3-2)


系数为:

        (3-3)


在历史数据出现曲率时,三次指数平滑模型预测值较二次指数平滑模型更加准确。
int ExponentialSmoothing(double x[], int len, int pre_time){ double weight =
0.6; double at = 0.0; double bt = 0.0; double ct = 0.0; double* onetime_pre =
(double *)malloc(len * sizeof(double)); double* twotime_pre = (double
*)malloc(len * sizeof(double)); double* threetime_pre = (double *)malloc(len *
sizeof(double)); double *y=(double *)malloc(pre_time*sizeof(double));
memset(onetime_pre, 0, len * sizeof(double)); memset(twotime_pre, 0, len *
sizeof(double)); memset(threetime_pre, 0, len * sizeof(double));
memset(y,0,pre_time*sizeof(double)); //一次指数平滑 onetime_pre[0] = x[0]; //init for
(int i = 1; i < len; i++) { onetime_pre[i] = weight * x[i] + (1 - weight) *
onetime_pre[i - 1]; } //二次指数平滑 twotime_pre[0] = (onetime_pre[0] +
onetime_pre[1] + onetime_pre[2]) / 3; //init for (int i = 1; i < len; i++) {
twotime_pre[i] = weight * onetime_pre[i] + (1 - weight) * twotime_pre[i - 1]; }
//三次指数平滑 threetime_pre[0] = (twotime_pre[0] + twotime_pre[1] + twotime_pre[2])
/ 3; //init for (int i = 1; i < len; i++) { threetime_pre[i] = weight *
twotime_pre[i] + (1 - weight) * threetime_pre[i - 1]; } //计算截距和斜率 at = 3 *
onetime_pre[len -1] - 3 * twotime_pre[len - 1] + threetime_pre[len - 1]; bt =
weight / (2 * (1 - weight) * (1 - weight)) * ((6 - 5 * weight) *
onetime_pre[len - 1] - 2 * (5 - 4 * weight) * twotime_pre[len - 1] + (4 - 3 *
weight) * threetime_pre[len - 1]); ct = (weight * weight) / (2 * (1 - weight)
*(1 - weight)) * (onetime_pre[len - 1] - 2 * twotime_pre[len - 1] +
threetime_pre[len - 1]); //printf("at = %f\n", at); //printf("bt = %f\n", bt);
for (int T = 0; T < pre_time; T++) { y[T] = at + bt * (T + 1) + ct * (T + 1) *
(T + 1); } double result=sumAllVectord(y,pre_time); if(result<0) result=0;
free(onetime_pre); free(twotime_pre); free(threetime_pre); free(y); return
floor(result); }

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信