指数平滑及python实现 用于预测下一个值

一般常用到的指数平滑法为一次指数平滑、二次指数平滑和三次指数平滑,高次指数平滑一般比较难见到,因此本文着重介绍了一次、二次和三次指数平滑的特点与不同。

一次指数平滑一般应用于直线型数据,且一次指数平滑具有滞后性,可以说明有明显的时间性、季节性。

二次指数平滑一般也应用于直线型,但是效果会比一次指数平滑好很多,也就相当于加强版的一次指数平滑。

三次指数平滑可以应用于抛物线型的数据,因为数据在二次平滑过后还是具有斜率,那么可以继续使用三次指数平滑。

初值:不管什么指数平滑都会有个初值,假如数据大于20项,那么初值就可以认定为第一个数据,或者利用下列公式计算也行;假如数据小于20项,则初始值为:
在这里插入图片描述
低于20项一般取3,大于20的看着取就行了。

一次指数平滑

​ 当时间序列数据没有明显的变化趋势,就可以使用一次指数平滑。实际就是对历史数据的加权平均,它可以用于任何一种没有明显函数规律但确实存在某种前后关联的时间序列的短期预测。

​ 但是一次指数平滑也具有一定的局限性:第一,预测值不能反映趋势变动、季节波动等有规律的变动;第二,这种方法多适用于短期预测,而不适合作中长期的预测;第三,由于预测值是历史数据的均值,因此与实际序列的变化相比有滞后现象。

​ 其预测公式如下:
在这里插入图片描述
其中,y∗t+1是t+1时期的预测值,yt是t时刻的实际值,y∗t是t时刻的预测值。
所以,在迭代的过程中,我们需要开一个list来存放y∗t。最后的预测值就是
在这里插入图片描述

取实际值的最后一个与预测值的最后一个就能预测出下一个时刻的值!
其中y∗0的确定一般有以下的规则:

如果数据小于20,一般取前三项的均值
大于20时,看情况调整第一项的值,一般取第一项就行,因为数据多,y∗0的取值对最后的预测结果影响不大
关于α的取值方法,请往下看。

二次指数平滑

​ 二次指数平滑是对一次指数平滑的再平滑。它适用于具线性趋势的时间数列。虽然一次指数平均在产生新的数列的时候考虑了所有的历史数据,但是仅仅考虑其静态值,即没有考虑时间序列当前的变化趋势。所以二次指数平滑一方面考虑了所有的历史数据,另一方面也兼顾了时间序列的变化趋势。

二次指数平滑的计算公式为:

指数平滑及python实现 用于预测下一个值_第1张图片
所以,实际上在程序上的操作就是在一次平滑的基础上再做一次指数平滑,其中我们需要两个list来存储一次平滑的值和二次平滑的值,通过对应的两次指数平滑,就可以求出对应的at,bt的值。最后调用公式在这里插入图片描述就可以做出预测,其中T是向后预测的周期,如向后预测一个周期(一天/一年等),那么T=1,往后预测两个就是T=2,以此类推。

三次指数平滑

​ 若时间序列的变动呈现出二次曲线趋势,则需要采用三次指数平滑法进行预测。实际上是在二次指数平滑的基础上再进行一次指数平滑。它与二次指数平滑的区别就是三次平滑还考虑到了季节性效应。

三次指数平滑的计算公式为:
指数平滑及python实现 用于预测下一个值_第2张图片

预测未来期的值的计算公式为:
在这里插入图片描述

关于平滑系数αα的取值
1、当时间序列呈现较稳定的水平趋势时,应选较小的α,一般可在0.05~0.20之间取值‘

2、当时间序列有波动,但长期趋势变化不大时,可选稍大的α值,常在0.1~0.4之间取值;

3、当时间序列波动很大,长期趋势变化幅度较大,呈现明显且迅速的上升或下降趋势时,宜选择较大的α值,如可在0.6~0.8间选值。以使预测模型灵敏度高些,能迅速跟上数据的变化。

4、当时间序列数据是上升(或下降)的发展趋势类型,α应取较大的值,在0.6~1之间。

# -*- coding: utf-8 -*-
'''
Exponential smooth(指数平滑)的手工实现(无第三方库)
Author : Kabuto_hui
Date   : 2018.04.19
'''

#指数平滑算法
def exponential_smoothing(alpha, s):
    '''
    一次指数平滑
    :param alpha:  平滑系数
    :param s:      数据序列, list
    :return:       返回一次指数平滑模型参数, list
    '''
    s_temp = [0 for i in range(len(s))]
    s_temp[0] = ( s[0] + s[1] + s[2] ) / 3
    for i in range(1, len(s)):
        s_temp[i] = alpha * s[i] + (1 - alpha) * s_temp[i-1]
    return s_temp

def compute_single(alpha, s):
    '''
    一次指数平滑
    :param alpha:  平滑系数
    :param s:      数据序列, list
    :return:       返回一次指数平滑模型参数, list
    '''
    return exponential_smoothing(alpha, s)

def compute_double(alpha, s):
    '''
    二次指数平滑
    :param alpha:  平滑系数
    :param s:      数据序列, list
    :return:       返回二次指数平滑模型参数a, b, list
    '''
    s_single = compute_single(alpha, s)
    s_double = compute_single(alpha, s_single)

    a_double = [0 for i in range(len(s))]
    b_double = [0 for i in range(len(s))]

    for i in range(len(s)):
        a_double[i] = 2 * s_single[i] - s_double[i]                    #计算二次指数平滑的a
        b_double[i] = (alpha / (1 - alpha)) * (s_single[i] - s_double[i])  #计算二次指数平滑的b

    return a_double, b_double

def compute_triple(alpha, s):
    '''
    三次指数平滑
    :param alpha:  平滑系数
    :param s:      数据序列, list
    :return:       返回三次指数平滑模型参数a, b, c, list
    '''
    s_single = compute_single(alpha, s)
    s_double = compute_single(alpha, s_single)
    s_triple = exponential_smoothing(alpha, s_double)

    a_triple = [0 for i in range(len(s))]
    b_triple = [0 for i in range(len(s))]
    c_triple = [0 for i in range(len(s))]

    for i in range(len(s)):
        a_triple[i] = 3 * s_single[i] - 3 * s_double[i] + s_triple[i]
        b_triple[i] = (alpha / (2 * ((1 - alpha) ** 2))) * ((6 - 5 * alpha) * s_single[i] - 2 * ((5 - 4 * alpha) * s_double[i]) + (4 - 3 * alpha) * s_triple[i])
        c_triple[i] = ((alpha ** 2) / (2 * ((1 - alpha) ** 2))) * (s_single[i] - 2 * s_double[i] + s_triple[i])

    return a_triple, b_triple, c_triple

if __name__ == "__main__":

    alpha = 0.8
    data = [i for i in range(100)]

    sigle = compute_single(alpha, data)

    print(alpha * data[-1] + (1 - alpha) * sigle[-1])

参考详细链接:指数平滑

你可能感兴趣的:(机器学习)