必威体育Betway必威体育官网
当前位置:首页 > IT技术

指数平滑法,附源码

时间:2019-09-05 17:40:00来源:IT技术作者:seo实验室小编阅读:52次「手机版」
 

指数平滑法

大部分公式内容来自:https://blog.csdn.net/nieson2012/article/details/51980943

实操部分有部分来自:https://blog.csdn.net/AlanconstantineLau/article/details/70173561

大部分公式也是自己码的,主要练习markdown公式,如有侵权务必告知本人。

简介

指数平滑法实际上是一种特殊的加权移动平均法,其加强了观察期近期观察值对预测值的作用,对不同时间的观察值所赋予的权数不等,从而加大了近期观察值的权数,其根据所取的权值alpha可改变曲线的变化速率。它不舍弃过去的数据,但是仅给予逐渐减弱的影响程度,即随着数据的远离,赋予逐渐收敛为零的权数。它是一种基于时间序列的预测方法,一般将其分为一次指数平滑法、二次指数平滑法和三次指数平滑法。


基本公式

st=αyt+(1−α)st−1" role="presentation">st=αyt+(1α)st1

其中S(t)为t时刻的平滑值,Y(t)为t时刻的实际值,α为平滑常数。

注意这个公式只是计算平滑系数,真正的预测还没开始。


一次指数平滑

yt+1′=αy(t)+(1−α)yt′" role="presentation">yt+1=αy(t)+(1α)yt

其中yt+1′为t+1期预测值,y(t)为t期实际值,yt′为t期预测值" role="presentation">yt+1t+1y(t)tytt

例题:

这里写图片描述

求下第16个月的销量y16" role="presentation">y16

这里只取α" role="presentation">α为0.5作为测试,并设平滑值:

s0(1)=y1+y2+y33=11.0" role="presentation">s0(1)=y1+y2+y33=11.0

则:

s1(1)=αy1+(1−α)s0(1)=0.5×10+0.5×11.0=10.5" role="presentation">s1(1)=αy1+(1α)s0(1)=0.5×10+0.5×11.0=10.5

s2(1)=αy1+(1−α)s1(1)=0.5×15+0.5×10.5=12.8" role="presentation">s2(1)=αy1+(1α)s1(1)=0.5×15+0.5×10.5=12.8

从父这种计算,得到

这里写图片描述

α" role="presentation">α为0.5,可得:

y16=0.5×29+(1∗0.5)×28.1=28.55" role="presentation">y16=0.5×29+(10.5)×28.1=28.55

系数α" role="presentation">α越小,平滑作用越强(这里没有举例,感兴趣的可以看上面提到的文章


二次指数平滑

先求出二次的平滑系数(非预测值):

st(2)=αst(1)+(1−α)st−1(2)" role="presentation">st(2)=αst(1)+(1α)st1(2)

其中:st(2)" role="presentation">st(2)为第t时刻的二次平滑值,st(1)" role="presentation">st(1)为相同周期的一次平滑值,st−1(2)" role="presentation">st1(2)为第t-1时刻的二次指数平滑值

预测模型

yt+T=at+btT" role="presentation">yt+T=at+btT

st(2)=αst(1)+(1−α)st−1(2)" role="presentation">st(2)=αst(1)+(1α)st1(2)

at=2st(1)−st(2)(注意上标)" role="presentation">at=2st(1)st(2)()

bt=a1−1(st(1)−st(2))" role="presentation">bt=a11(st(1)st(2))

具体例子不再详举,公式好难打,有需要的回去看上面提到的文章。还有注意这里的a和b,a并非α" role="presentation">α,这两个都是二次平滑新的参数,三次平滑还会多一个参数。


三次指数平滑

废话不多说,直接求平滑系数(其实只是再把二次的平滑系数拿来平滑一次),也就是说,在求当前平滑系数sti" role="presentation">sti的时候,可以把前面次的平滑系数sti−1" role="presentation">sti1像一次平滑那样,看成y" role="presentation">y来求,只是简单重复而已。

st(3)=αst(2)+(1−α)st−1(3)" role="presentation">st(3)=αst(2)+(1α)st1(3)

预测模型:

yt+T=at+btT+ctT2" role="presentation">yt+T=at+btT+ctT2

at=3st(1)−3st(2)+3st(3)" role="presentation">at=3st(1)3st(2)+3st(3)

bt=α2(1−α)2[(6−5α)st(1)−2(5−4α)st(2)+(4−3α)st(3)]" role="presentation">bt=α2(1α)2[(65α)st(1)2(54α)st(2)+(43α)st(3)]

ct=α22(1−α)2[st(1)−2st(2)+st(3)]" role="presentation">ct=α22(1α)2[st(1)2st(2)+st(3)]

第一个公式为预测方法,后面三个均为系数求解,注意这里的T,是以和t相差间隔为度量,即如果t是1996,要预测的是1997,那么这里的T就是1,而非1997。

这一系列公式,所有的平滑系数都用上了,也就是三次平滑考虑得最多,一次和二次平滑系数是其前提,没有则无法求解。

直接引用参考链接1中的例子:我国某种耐用消费品1996年至2006年的销售量如表所示,试预测2007、2008年的销售量。 三次指数平滑的计算表:

这里写图片描述

设最初的平滑系数为前三个的平均(要用来计算后面的)

这里写图片描述

计算一次、二次、三次所有的平滑值

这里写图片描述

带入前面提到的公式中

这里写图片描述

因此第一个公式稍微具体一天有

这里写图片描述

预测2007(T=1)和2008(T=2)年

这里写图片描述


加权系数α" role="presentation">α的选择

在指数平滑法中,预测成功的关键是a的选择。a的大小规定了在新预测值中新数据和原预测值所占的比例。a值愈大,新数据所占的比重就愈大,原预测值所占比重就愈小,反之亦然。



代码实现任务

参考的是另一个链接

给定国家社科基金1995-2015年立项数据,要求预测2016和2018立项数量

#year time_id number
1994 1 10
1995 2 3
1996 3 27
1997 4 13
1998 5 12
1999 6 13
2000 7 14
2001 8 23
2002 9 32
2003 10 30
2004 11 36
2005 12 40
2006 13 58
2007 14 51
2008 15 73
2009 16 80
2010 17 106
2011 18 127
2012 19 135
2013 20 161
2014 21 149
2015 22 142

代码部分

# coding=utf-8
import matplotlib.pyplot as plt


def calc_next_s(alpha, s):
    # 计算s的值,哪怕指数的次数再高,计算的流程都是一样的
    s2 = [0 for i in range(len(s))]
    # 我是取前三个的平均来初始化s0
    s2[0] = sum(s[0:3]) / float(3)
    for i in range(1, len(s2)):
        # 跳过第一个,因为第一个之前没有可用来预测的参数
        s2[i] = alpha * s[i] + (1 - alpha) * s2[i - 1]
        # 这里其实有点小bug,也就是s2[0]到底是保留当第一个,
        # 还是用来做第0个,只用来预测新的s2值,之后不保留进列表
    return s2


def exponential_smoothing():
    # 设定alpha,这是平滑系数
    alpha = 0.5

    # 数据载入可选择1
    data = []
    # 读取文件
    with open('data.txt', 'r') as f:
        lines = f.readlines()
        for line in lines:
            data.APPend(line.strip('\r\n').split())
    # 提取数据文件中的值
    data_value = [int(ele[2]) for ele in data if ele[2].isdigit()]

    # 数据载入可选择2
    # data_value = [10, 15, 8, 20, 10, 16, 18, 20, 22, 24, 20, 26, 27, 29, 29]  # 文章第一部分数据,实现和理论稍微有偏差


    # 以下为系数求解,这些都是根据定义的公式得来的:
    # 如果不懂,建议多看几遍公式
    # 一次平滑系数,只有一个s,没算上alpha
    s1 = calc_next_s(alpha, data_value)
    # 二次平滑系数,有一个s和两个系数
    s2 = calc_next_s(alpha, s1)
    a2 = [(2 * s1[i] - s2[i]) for i in range(len(s1))]
    b2 = [(alpha / (1 - alpha) * (s2[i] - s1[i])) for i in range(len(s1))]

    # 三次平滑系数,有一个s和三个系数
    s3 = calc_next_s(alpha, s2)
    a3 = [(3 * s1[i] - 3 * s2[i] + s3[i]) for i in range(len(s3))]
    b3 = [((alpha / (2 * (1 - alpha) ** 2)) * (
            (6 - 5 * alpha) * s1[i] - 2 * (5 - 4 * alpha) * s2[i] + (4 - 3 * alpha) * s3[i])) for i in
          range(len(s3))]
    c3 = [(alpha ** 2 / (2 * (1 - alpha) ** 2) * (s1[i] - 2 * s2[i] + s3[i])) for i in range(len(s3))]

    # 以下为预测部分
    # 这是一次的,是按我自己理解的,感觉不一定是这样求的
    # 我没认真细究,我觉得那个s1要一次次求,所以这里只求了一天
    # 如有什么疏漏欢迎指正
    s_single = [0 for i in range(len(s1))]
    for i in range(1, len(s2)):
        s_single[i] = data_value[i - 1] + (1 - alpha) * s1[i - 1]  # 这里有个和时间差有关的系数
    predict_single = [0 for i in range(1)]
    for i in range(len(predict_single)):
        predict_single[i] = alpha * data_value[-1] + (1 - alpha) * s1[-1]
    s_single.extend(predict_single)

    # 二次的预测
    # 和原始数据横坐标相同的那些天
    s_double = [0 for i in range(len(s2))]
    for i in range(1, len(s2)):
        s_double[i] = a2[i - 1] + b2[i - 1] * 1  # 这里有个和时间差有关的系数
    # 预测未来两年,即新增未来两年的坐标
    predict_double = [0 for i in range(2)]
    for i in range(len(predict_double)):
        predict_double[i] = a2[-1] + b2[-1] * (i + 1)
    # 把预测的两年和原本的组合放一起
    s_double.extend(predict_double)

    # 三次的预测
    s_triple = [0 for i in range(len(s3))]
    for i in range(1, len(s3)):
        s_triple[i] = a3[i - 1] + b3[i - 1] * 1 + c3[i - 1] * (1 ** 2)
    # 预测未来两年,即新增未来两年的坐标
    predict_triple = [0 for i in range(2)]
    for i in range(len(predict_triple)):
        predict_triple[i] = a3[-1] + b3[-1] * (i + 1) + c3[-1] * (1 ** (i + 1))
    s_triple.extend(predict_triple)

    # 绘制所有的曲线
    plot(data_value, s_single, s_double, s_triple)


def plot(origin_data, s_single, s_double, s_triple):
    # plot的第一个参数看似复杂,其实只是从0-n,变成年份-(年份+n)而已
    plt.plot([i + 1994 for i in range(len(origin_data))], origin_data, color='blue', label='origin data')
    plt.plot([i + 1994 for i in range(len(s_single))], s_single, color='red', label='single smoothing')
    plt.plot([i + 1994 for i in range(len(s_double))], s_double, color='green', label='double smoothing')
    plt.plot([i + 1994 for i in range(len(s_triple))], s_triple, color='black', label='triple smoothing')
    plt.legend(loc='lower right')
    plt.xlabel('year')
    plt.ylabel('value')
    plt.show()


if __name__ == '__main__':
    exponential_smoothing()

运行结果

这里写图片描述


后话

这次指数平滑模型,没能带给我好运气,也是我自己不会使用。其实它真的简单好用,只是对于波动非常大的数据,如果不是只预测某一天,最好还是选连续的天数作为特征。特征工程,厉害了。

相关阅读

《创造101》的小姐姐们谁人气更旺? 来搜狗指数一探究竟

最近,国内首档女团青春成长节目《创造101》迅速走红,激起全民追捧热潮。节目中极具话题度的明星导师、颜好条顺又个性十足的选手、

体重指数

//问题 G: 体重指数//时间限制: 1 Sec  内存限制: 128 MB//提交: 217  解决: 99//[提交][状态][讨论版][命题人:60099]//题目描

微信指数怎么看懂?教你怎么看懂微信指数

微信指数怎么看懂?教你怎么看懂微信指数。相信很多小伙伴都不太懂什么是微信指数吧,接下来小编就向大家介绍一下什么是微信指数,微

指数分布

指数分布 当一个随机变量XXX ~ exp(λ)exp(\lambda)exp(λ)时,它的密度函数为:f(x)={λe−λx,(x≥0)0,(x<0). f(x)=\left\{ \b

关于微信指数,你可能最想了解的9个问题

关于微信指数,也许你有许多的好奇与疑问,微信官方给出了一些解答,请看以下正文。昨晚,在大家观战国足战胜韩足正酣时,而“微信指数”功

分享到:

栏目导航

推荐阅读

热门阅读