指数平滑算法介绍及代码实现

一、一阶指数平滑

  • 一阶指数平滑,也称为一次指数平滑或简单指数平滑(Simple Exponential Smoothing, SES),是时间序列预测中的一种方法。这种方法适用于没有明显趋势和季节性成分的时间序列数据。
  • 一阶指数平滑的基本思想是最近的观测值比远期的观测值在预测未来时更为重要。因此,这种方法给予近期的数据更高的权重,而远期数据的权重则按指数规律递减。
    一阶指数平滑的计算包括以下几个步骤:
  • 选择平滑系数(alpha):平滑系数决定了指数递减的速度,其值通常在0和1之间。alpha越接近1,模型对近期数据的关注越多;alpha越接近0,模型对历史数据的关注越多。
  • 初始化:对于数据序列的初始值,如果数据点较多(大于20个),可以取第一个数据点作为初始平滑值;如果数据点较少,可以取前几个数据点的平均值。
  • 平滑计算:一旦确定了alpha和初始值,就可以用以下公式进行平滑计算:
    预测值 = a * 实际值 + (1 - a) * 上一期的预测值
from visitOracle import visitOracle
import pandas as pd
import numpy as np
from math_tool import *
# 时间序列指数平滑算法

###一阶指数平滑
## datas: 待预测的原始数据
## alfa: 平滑系数
## initial: 平滑初始值
## 返回结果:一次指数平滑结果
def expenontionSmooth(test_data , alfa , initial):
    expenontionResult = []
    expenontionResult.append(initial)
    for i in range(len(test_data) -1):
        # 指数平滑公式
        tempResult = alfa * test_data[i+1] + (1 - alfa) * expenontionResult[i] 
        expenontionResult.append(round(tempResult , 2))
    return expenontionResult

二、二次平滑指数
当时间数列无明显的趋势变化,可用一次指数平滑预测。其预测公式为:

yt+1’=a*yt+(1-a)*yt’ 式中,

• yt+1’–t+1期的预测值,即本期(t期)的平滑值St ;

• yt–t期的实际值;

• yt’–t期的预测值,即上期的平滑值St-1 。
三、二次指数平滑预测

1) a为加权系数;

2) 指数平滑法对实际序列具有平滑作用,权系数(平滑系数)越小,平滑作用越强,但是对实际数据的变动反映较迟缓;

3) 在实际序列的线性变动部分,指数平滑值序列出现一定的滞后偏差的程度随着权系数(平滑系数)的增大而减少;但当时间序列的变动出现直线趋势时,用一次指数平滑法来进行预测仍将存在着明显的滞后偏差。因此,也需要进行修正。

4) 修正的方法也是在一次指数平滑的基础上再进行二次指数平滑,利用滞后偏差的规律找出曲线的发展方向和发展趋势,然后建立直线趋势预测模型,故称为二次指数平滑法。

在一次指数平滑的基础上得二次指数平滑 的计算公式为:

在这里插入图片描述

• 式中: St(2)——第t周期的二次指数平滑值;

• St(1)——第t周期的一次指数平滑值;

• St-1(2)——第t-1周期的二次指数平滑值;

• a ——加权系数(也称为平滑系数)。

二次指数平滑法是对一次指数平滑值作再一次指数平滑的方法。它不能单独地进行预测,必须与一次指数平滑法配合,建立预测的数学模型,然后运用数学模型确定预测值。
二次指数平滑法是对一次指数平滑值作再一次指数平滑的方法。它不能单独地进行预测,必须与一次指数平滑法配合,建立预测的数学模型,然后运用数学模型确定预测值。

二次指数平滑数学模型:
在这里插入图片描述
根据二次平滑指数数学模型进行计算a、b值。
python代码如下

###计算二阶指数平滑模型的参数
## datas: 待预测的原始数据
## alfa: 平滑系数
## initial: 平滑初始值
## 返回结果:二次指数平滑所对应的参数值
def paramCompute_TwoOrder(test_data, alfa,initial) :
    param0 = []     #param0: 存放各个时刻的截距
    param1 = []     #param1: 存放各个时刻的斜率
    ## 得到一次指数平滑结果
    SmoothResult_oneOrder = expenontionSmooth(test_data , alfa , initial)
    ## 得到二次指数平滑结果
    SmoothResult_twoOrder = expenontionSmooth(SmoothResult_oneOrder , alfa , SmoothResult_oneOrder[0] *1.1) 
    for i in range(len(SmoothResult_oneOrder)):
        # 截距计算公式
        param0_temp = 2 * SmoothResult_oneOrder[i] - SmoothResult_twoOrder[i]
        # 斜率计算公式
        param1_temp =( alfa / (1- alfa ) ) * (SmoothResult_oneOrder[i] - SmoothResult_twoOrder[i]);
        param0.append(param0_temp)
        param1.append(param1_temp)
    params = {'param0':param0 , 'param1':param1}
    params = pd.DataFrame(params)
    return params
#######计算二阶指数平滑的预测结果
## datas: 待预测数据
## alfa: 平滑系数
## predictcnt: 预测期数
## initial: 平滑初始值
## return: 返回预测结果:数据的最后predictCnt为预测值
def predictValueOfTwoOrder(test_data, alfa,  predictCnt, initial):
    params_twoOrder = paramCompute_TwoOrder(test_data, alfa,initial)
    cnt = len(params_twoOrder) 
    # 取最后一个时刻的截距
    param0 = params_twoOrder.iloc[cnt-1,]['param0']
    # 取最后时刻的斜率
    param1 = params_twoOrder.iloc[cnt-1,]['param1']
    predictValue = []     # 存放预测结果
    for i in range(cnt + predictCnt):
        tempValue = param0 + (i- len(test_data) + 1) * param1;
        predictValue.append(round(tempValue,2))
    return predictValue

四、三次指数平滑
若时间序列的变动呈现出二次曲线趋势,则需要采用三次指数平滑法进行预测。三次指数平滑是在二次指数平滑的基础上再进行一次平滑,其计算公式为:
在这里插入图片描述
三次指数平滑法的预测模型为:
在这里插入图片描述
python代码如下:

####计算三次指数平滑模型中3个参数
#### param datas        训练数据
#### param alfa         平滑参数
####return           返回结果三阶指数平滑的3个参数
def paramComputeOfThreeOrder(test_data, alfa, initial):
    param0 = []               # 存放参数a0
    param1 = []               # 存放参数a1
    param2 = []               # 存放参数a2
    # 得到一阶指数平滑结果
    SmoothResult_oneOrder = expenontionSmooth(test_data , alfa , initial);
    ## 得到二次指数平滑结果
    SmoothResult_twoOrder = expenontionSmooth(SmoothResult_oneOrder , alfa , SmoothResult_oneOrder[0] *1.1) 
    ## 得到三次指数平滑结果
    SmoothResult_threeOrder = expenontionSmooth(SmoothResult_twoOrder , alfa , SmoothResult_twoOrder[0] *1.1)
    for i in range(len(test_data)):
        param0_temp = 3 * SmoothResult_oneOrder[i] - 3 * SmoothResult_twoOrder[i] + SmoothResult_threeOrder[i]
        param1_temp = (alfa /(2 * (1 - alfa) * (1 - alfa))) *  ((6 - 5*alfa) * SmoothResult_oneOrder[i] - 
	   			               2 * (5 - 4 * alfa) * SmoothResult_twoOrder[i] 
	   			    		   + (4 - 3 *alfa )* SmoothResult_threeOrder[i])
        param2_temp = (alfa * alfa / (2 * (1 - alfa) * (1 - alfa))) *(SmoothResult_oneOrder[i] -
	   			           2 * SmoothResult_twoOrder[i] + SmoothResult_threeOrder[i]);
        param0.append(round(param0_temp,2))
        param1.append(round(param1_temp,2))
        param2.append(round(param2_temp,2))
    params = {'param0': param0 , 'param1':param1 , 'param2':param2}
    params = pd.DataFrame(params)
    return params
####  三次指数平滑模型预测结果
## datas: 待预测数据
## alfa: 平滑系数
## predictcnt: 预测期数
## initial: 平滑初始值   
## 返回预测结果    
def predictValueOfThreeOrder( test_data,  alfa,  predictCnt, initial):
    params_threeOrder = paramComputeOfThreeOrder(test_data, alfa, initial)
    cnt = len(params_threeOrder)
    # 取最后一个时刻的a
    param0 = params_threeOrder.iloc[cnt-1,]['param0']
    # 取最后时刻的b
    param1 = params_threeOrder.iloc[cnt-1,]['param1']
     # 取最后时刻的c
    param2 = params_threeOrder.iloc[cnt-1,]['param2']
    predictValue = []     # 存放预测结果
    for i in range(cnt + predictCnt):
        tempValue = param0 + (i- len(test_data) + 1) * param1 + (i- len(test_data) + 1) * (i- len(test_data) + 1) * param2
        predictValue.append(round(tempValue,2)) 
    return predictValue

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

指数平滑法的缺点:
• (1)对数据的转折点缺乏鉴别能力,但这一点可通过调查预测法或专家预测法加以弥补。

• (2)长期预测的效果较差,故多用于短期预测。

指数平滑法的优点:

• (1)对不同时间的数据的非等权处理较符合实际情况。

• (2)实用中仅需选择一个模型参数a 即可进行预测,简便易行。

• (3)具有适应性,也就是说预测模型能自动识别数据模式的变化而加以调整。
六、自动选择最后的平滑参数及相应的平滑阶数

## 系统选择最好的平滑系数和平滑初始值
## datas: 待预测数据
## predictCnt : 预测期数
## 返回结果: 相对误差最小的一组预测结果    
def  selectSmoothMethod(test_data , predictCnt):
     alfaLst = []
     alfaCnt = 20     # 由于alfa在0~1之间取值,每隔1/alfaCnt 采样一次,采集alfaCnt - 1次
     alfaStep = 1 / alfaCnt
     for i in range(alfaCnt - 1):
         alfaLst.append(round(alfaStep*(i+1) , 2))
     ##在原始数据第一个值的(datas[0])* (1 - 20%) ~ (datas[0] * (1 + 20%))之间以步长( end - start ) / 100 为步长进行遍历    
     start_initial = test_data[0] * (1 - 0.2)
     end_initial = test_data[0] * (1 + 0.2)
     # 采样次数
     initialCnt =  100;  
     # 采样的步长        
     initialStep = (end_initial - start_initial ) / initialCnt
     initialLst = []
     for i in range(initialCnt):
         initialLst.append(round(start_initial + i * initialStep ,2))
     #### 存放二阶预测的相对误差
     relativeErrorOfTwoOrder = np.zeros((alfaCnt -1 , initialCnt) , dtype = np.double)
     ### 存放三阶预测的相对误差
     relativeErrorOfThreeOrder = np.zeros((alfaCnt - 1, initialCnt) , dtype = np.double)
     for i in range(alfaCnt -1):
         for j in range(initialCnt):
              ## 二阶指数平滑的预测结果
              ## 此时resultOfTwoOrder的值为当 alfa = arrayAlfa[i] , initial = initialArray[j]的值
	  			    ## 遍历所有可能的alfa和initial,得到预测结果,计算每个结果的相对误差。
              ## 得到二次指数平滑结果
              predictResult_twoOrder = predictValueOfTwoOrder(test_data, alfaLst[i],  predictCnt, initialLst[j]) 
              ## 得到三次指数平滑结果
              predictResult_threeOrder = predictValueOfThreeOrder(test_data, alfaLst[i],  predictCnt, initialLst[j]) 
              ### 计算平滑系数等于alfaLst[i] , 平滑初始值 =  initialLst[j]时,预测结果和原始数据之间的相对误差
              relativeErrorOfTwoOrder[i][j] =  cal_relativeError(test_data, predictResult_twoOrder)
              relativeErrorOfThreeOrder[i][j] = cal_relativeError(test_data, predictResult_threeOrder)
  
     ## 取得二阶预测的相对误差最小值
     ## 取得三阶预测的相对误差最小的值
     minest_error_twoOrder =round( find_martrix_min_value(relativeErrorOfTwoOrder) ,5)
     minest_error_threeOrder =round( find_martrix_min_value(relativeErrorOfThreeOrder) , 5)
     ## 在二阶、三阶中找出最小的误差
     bestPredictResult = []
     minest_error = min([minest_error_twoOrder, minest_error_threeOrder])
     for i in range(alfaCnt -1):
         for j in range(initialCnt):
             if (minest_error == round( relativeErrorOfTwoOrder[i][j] ,5)):
                  bestPredictResult=(predictValueOfTwoOrder(test_data, alfaLst[i],  predictCnt, initialLst[j]))
             if(minest_error ==round( relativeErrorOfThreeOrder[i][j] ,5)) :
                  bestPredictResult=(predictValueOfThreeOrder(test_data, alfaLst[i],  predictCnt, initialLst[j]))
     return bestPredictResult    

参考博客:https://blog.csdn.net/hqr20627/article/details/79407867

  • 25
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值