一、一阶指数平滑
- 一阶指数平滑,也称为一次指数平滑或简单指数平滑(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 = [] # 存放参数a0param1 = [] # 存放参数a1param2 = [] # 存放参数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)# 取最后一个时刻的aparam0 = params_threeOrder.iloc[cnt-1,]['param0']# 取最后时刻的bparam1 = params_threeOrder.iloc[cnt-1,]['param1']# 取最后时刻的cparam2 = 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) * param2predictValue.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 / alfaCntfor 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 ) / initialCntinitialLst = []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