目錄
引言
數(shù)據(jù)格式
運(yùn)行代碼?
Holt-Winters模型主體
程序入口
參數(shù)講解
開(kāi)始訓(xùn)練
預(yù)測(cè)結(jié)果
?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-751784.html
引言
話不多說(shuō)上來(lái)先上預(yù)測(cè)精度分析圖,其中MAE的誤差大概在0.11,以下數(shù)據(jù)均是預(yù)測(cè)未知數(shù)據(jù),而不是訓(xùn)練數(shù)據(jù)的預(yù)測(cè)圖。
?
開(kāi)始之前我們先來(lái)簡(jiǎn)單了解一下Holt-Winters模型
Holt-Winters模型,也稱為三重指數(shù)平滑模型,是一種經(jīng)典的時(shí)間序列預(yù)測(cè)模型,用于處理具有趨勢(shì)和季節(jié)性的時(shí)間序列數(shù)據(jù)。
Holt-Winters模型基于指數(shù)平滑法,通過(guò)對(duì)歷史數(shù)據(jù)進(jìn)行加權(quán)平均來(lái)預(yù)測(cè)未來(lái)的值。它使用三個(gè)指數(shù)平滑系數(shù)來(lái)估計(jì)未來(lái)的趨勢(shì)、季節(jié)性和平穩(wěn)項(xiàng),從而可以對(duì)未來(lái)的值進(jìn)行預(yù)測(cè)。
Holt-Winters模型的三個(gè)指數(shù)平滑系數(shù)分別為:α、β和γ。其中,α表示對(duì)當(dāng)前觀測(cè)值的加權(quán)系數(shù),β表示對(duì)趨勢(shì)的加權(quán)系數(shù),γ表示對(duì)季節(jié)性的加權(quán)系數(shù)。這些系數(shù)可以通過(guò)利用K-折交叉驗(yàn)證最小化平均絕對(duì)誤差或平均平方誤差來(lái)確定。
Holt-Winters模型大致可以分為三種類型:加法模型、乘法模型和季節(jié)性模型。加法模型適用于季節(jié)性變化的幅度相對(duì)穩(wěn)定的情況,乘法模型適用于季節(jié)性變化的幅度隨著趨勢(shì)的變化而變化的情況,季節(jié)性模型則適用于季節(jié)性變化的周期相對(duì)穩(wěn)定的情況。
本文主要選擇一種模型來(lái)進(jìn)行實(shí)現(xiàn)(季節(jié)性模型)同時(shí)利用K-折交叉驗(yàn)證法來(lái)確定其中三個(gè)平滑系數(shù)α、β和γ以驗(yàn)證最好的系數(shù),從而達(dá)到最高的預(yù)測(cè)精度極限。
下面來(lái)接介紹一下什么是K-折交叉驗(yàn)證
K-折交叉驗(yàn)證(K-fold cross-validation)是一種常用的模型評(píng)估方法,用于評(píng)估機(jī)器學(xué)習(xí)模型的性能和泛化能力。它將原始數(shù)據(jù)集分成K個(gè)子集,稱為“折疊”(fold),其中K-1個(gè)子集用于訓(xùn)練模型,1個(gè)子集用于測(cè)試模型。這個(gè)過(guò)程重復(fù)K次,每個(gè)子集都會(huì)輪流作為測(cè)試集,最終得到K個(gè)模型的性能評(píng)估結(jié)果,這些結(jié)果可以平均或加權(quán)平均得到模型的最終性能評(píng)估結(jié)果。
K-折交叉驗(yàn)證的優(yōu)點(diǎn)是可以有效地利用數(shù)據(jù)集,減少因數(shù)據(jù)劃分不合理而引入的偏差,提高模型的泛化能力。同時(shí),K-折交叉驗(yàn)證可以避免過(guò)擬合和欠擬合等問(wèn)題,提高模型的穩(wěn)定性和可靠性。
數(shù)據(jù)格式
在正式開(kāi)始之前需要先了解一下,holt-winter模型是單元變量預(yù)測(cè)模型,所以其只接受單個(gè)時(shí)間變量的時(shí)間序列預(yù)測(cè),所以其數(shù)據(jù)只需要一列即可,就是你需要預(yù)測(cè)的數(shù)據(jù)我們這里拿官方的數(shù)據(jù)ETTh1來(lái)進(jìn)行舉例?
數(shù)據(jù)是這種格式即可,當(dāng)然你也可以只有OT一列數(shù)據(jù)也可以,但是你要確保你的數(shù)據(jù)要符合時(shí)間序列,因?yàn)槟愕捻樞虿荒軌虼騺y,因?yàn)槲覀冃枰獣r(shí)間date這一列主要是為了確保數(shù)據(jù)是有序的,當(dāng)然如果你確定你的數(shù)據(jù)是有序的你也可以只讀取進(jìn)來(lái)一列數(shù)據(jù)即可?。?!?
運(yùn)行代碼?
Holt-Winters模型主體
大家可以新建一個(gè)py文件將以下所有代碼復(fù)制進(jìn)去加上你的數(shù)據(jù)即可運(yùn)行出結(jié)果??!
import pandas as pd
import numpy as np
from scipy.optimize import minimize # 優(yōu)化函數(shù)
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import TimeSeriesSplit
class HoltWinters:
def __init__(self, series, slen, alpha, beta, gamma, n_preds, scaling_factor=1.96):
self.series = series
self.slen = slen
self.alpha = alpha
self.beta = beta
self.gamma = gamma
self.n_preds = n_preds
self.scaling_factor = scaling_factor
def initial_trend(self):
"""
初始化趨勢(shì),使用第一個(gè)原始數(shù)據(jù)周期內(nèi)的數(shù)據(jù)
依據(jù)現(xiàn)有的數(shù)據(jù),除非輸入的原始數(shù)據(jù)發(fā)生變化,否則為常數(shù)
:return: 初始化的趨勢(shì)
"""
sum = 0.0
for i in range(self.slen):
sum += float(self.series[i + self.slen] - self.series[i]) / self.slen
return sum / self.slen
def initial_seasonal_components(self):
"""
初始化季節(jié)性參數(shù)
:return: 季節(jié)性對(duì)于當(dāng)周期平均值的平均變化值
"""
seasonals = {}
season_averages = []
# 現(xiàn)有數(shù)據(jù)的周期個(gè)數(shù)
n_seasons = int(len(self.series) / self.slen)
# let's calculate season averages
# 最后一個(gè)周期會(huì)有稍微的影響,但影響不大
# 每個(gè)周期平均值,從第一個(gè)周期開(kāi)始,共有n個(gè)周期的數(shù)據(jù)
for j in range(n_seasons):
season_averages.append(sum(self.series[self.slen * j:self.slen * j + self.slen]) / float(self.slen))
# let's calculate initial values
# 周期中第i天的季節(jié)性增長(zhǎng)(對(duì)比周期內(nèi)的平均值)
# 數(shù)據(jù)個(gè)數(shù)為一個(gè)周期的長(zhǎng)度,index為一個(gè)周期內(nèi)的第幾個(gè)值,從0開(kāi)始
# 與原始數(shù)據(jù)相關(guān),并不是一個(gè)固定值
for i in range(self.slen):
sum_of_vals_over_avg = 0.0
for j in range(n_seasons):
sum_of_vals_over_avg += self.series[self.slen * j + i] - season_averages[j]
seasonals[i] = sum_of_vals_over_avg / n_seasons
return seasonals
def triple_exponential_smoothing(self):
"""
三次指數(shù)平滑
:return:
"""
# 預(yù)測(cè)結(jié)果
self.result = []
# 平滑值
self.Smooth = []
# 季節(jié)性
self.Season = []
# 趨勢(shì)性
self.Trend = []
# 預(yù)測(cè)標(biāo)準(zhǔn)差
self.PredictedDeviation = []
self.UpperBond = []
self.LowerBond = []
# 對(duì)于當(dāng)周期的平均值,每一時(shí)刻的平均變化值,為初始值
seasonals = self.initial_seasonal_components()
for i in range(len(self.series) + self.n_preds):
if i == 0: # components initialization
smooth = self.series[0]
trend = self.initial_trend()
self.result.append(self.series[0])
self.Smooth.append(smooth)
self.Trend.append(trend)
self.Season.append(seasonals[i % self.slen])
self.PredictedDeviation.append(0)
self.UpperBond.append(self.result[0] +
self.scaling_factor *
self.PredictedDeviation[0])
self.LowerBond.append(self.result[0] -
self.scaling_factor *
self.PredictedDeviation[0])
continue
if i >= len(self.series): # predicting
m = i - len(self.series) + 1
self.result.append((smooth + m * trend) + seasonals[i % self.slen])
# self.result.append(max(0,min(1, (smooth + m * trend) + seasonals[i % self.slen])))
# when predicting we increase uncertainty on each step
# 每一步增加預(yù)測(cè)的波動(dòng)性
self.PredictedDeviation.append(self.PredictedDeviation[-1] * 1.01)
else:
val = self.series[i]
last_smooth, smooth = smooth, self.alpha * (val - seasonals[i % self.slen]) + (1 - self.alpha) * (
smooth + trend)
trend = self.beta * (smooth - last_smooth) + (1 - self.beta) * trend
seasonals[i % self.slen] = self.gamma * (val - smooth) + (1 - self.gamma) * seasonals[i % self.slen]
self.result.append(smooth + trend + seasonals[i % self.slen])
# self.result.append(max(0,min(1, smooth + trend + seasonals[i % self.slen])))
# Deviation is calculated according to Brutlag algorithm.
self.PredictedDeviation.append(self.gamma * np.abs(self.series[i] - self.result[i])
+ (1 - self.gamma) * self.PredictedDeviation[-1])
self.UpperBond.append(self.result[-1] +
self.scaling_factor *
self.PredictedDeviation[-1])
self.LowerBond.append(self.result[-1] -
self.scaling_factor *
self.PredictedDeviation[-1])
self.Smooth.append(smooth)
self.Trend.append(trend)
self.Season.append(seasonals[i % self.slen])
def timeseriesCVscore(params, series, loss_function=mean_squared_error, slen=7):
"""
Returns error on CV
params - vector of parameters for optimization
series - dataset with timeseries
slen - season length for Holt-Winters model
"""
# errors array
errors = []
values = series.values
alpha, beta, gamma = params
# set the number of folds for cross-validation
# tscv = TimeSeriesSplit(n_splits=50, test_size=4)
tscv = TimeSeriesSplit(n_splits=5, test_size=4)
# iterating over folds, train model on each, forecast and calculate error
for train, test in tscv.split(values):
model = HoltWinters(series=values[train], slen=slen,
alpha=alpha, beta=beta, gamma=gamma, n_preds=len(test))
model.triple_exponential_smoothing()
predictions = model.result[-len(test):]
actual = values[test]
error = loss_function(predictions, actual)
errors.append(error)
return np.mean(np.array(errors)) # 返回了一個(gè)損失函數(shù)的平均值
以上的部分就是Holt-Winters的程序內(nèi)部,其中有一些個(gè)人閱讀時(shí)候的個(gè)人理解,大家可以在閱讀時(shí)候進(jìn)行一個(gè)參考,
程序入口
下面的代碼就是程序的入口,我們復(fù)制粘貼到文件的最后面即可,下面我將介紹其中每一行的具體含義??!
if __name__ == '__main__':
data = pd.read_csv('')
# initializing model parameters alpha, beta and gamma
cycle = '在這里輸入你數(shù)據(jù)的周期'
pre_len = '這里輸入你要預(yù)測(cè)未來(lái)多久的數(shù)據(jù)'
# Minimizing the loss function
opt = minimize(timeseriesCVscore, x0=[0, 0, 0],
args=(data, mean_squared_error,),
method="TNC", bounds=((0, 1), (0, 1), (0, 1))
)
# Take optimal values...
alpha, beta, gamma = opt.x
model = HoltWinters(data, slen=cycle,
alpha=alpha,
beta=beta,
gamma=gamma,
n_preds=pre_len, scaling_factor=2)
model.triple_exponential_smoothing()
print(model.result)
?
參數(shù)講解
?首先data = pd.read_csv('')這一行很好理解就是讀取你的數(shù)據(jù),首先要求你的數(shù)據(jù)需要是csv格式的文件,然后讀取來(lái)的數(shù)據(jù)要滿足第二節(jié)所述的數(shù)據(jù)格式(如果你的文件是其他格式你也可以更換類似于read_excel()即可)
data = pd.read_csv('')
當(dāng)我們將數(shù)據(jù)讀取進(jìn)來(lái)之后,我們可以對(duì)數(shù)據(jù)進(jìn)行一個(gè)按照時(shí)間排序的操作(如果你的數(shù)據(jù)只有目標(biāo)值列而沒(méi)有時(shí)間列則忽略掉本段代碼) 這一段代碼如果你們沒(méi)有也可以運(yùn)行如果需要排序則可以自己復(fù)制粘貼到對(duì)應(yīng)位置即可
data.sort_values(by=['date'], inplace=True)
之后的兩行,這兩行是一個(gè)是你數(shù)據(jù)擁有的周期性,因?yàn)閔olt-winter模型主要的參數(shù)還是你數(shù)據(jù)的一個(gè)周期來(lái)預(yù)測(cè)未來(lái)某一時(shí)段的數(shù)據(jù),所有你要知道你數(shù)據(jù)所擁有的周期性,可以通過(guò)數(shù)據(jù)建模的方式或者根據(jù)你的經(jīng)驗(yàn)來(lái)分析(如果大家不會(huì)可以評(píng)論區(qū)留言我可以給大家出用powerbi,matplotlib,excel來(lái)建模從而分析數(shù)據(jù)的教程)
cycle = '在這里輸入你數(shù)據(jù)的周期'
pre_len = '這里輸入你要預(yù)測(cè)未來(lái)多久的數(shù)據(jù)'
?這一段代碼如果大家了解深度學(xué)習(xí)就可以理解為模型訓(xùn)練的一個(gè)過(guò)程,其中
timeseriesCVscore是一個(gè)K-折交叉驗(yàn)證的方法來(lái)求出損失值最小的方法,
x0就是Holt-Winters模型的三個(gè)參數(shù)α、β和γ我們初始時(shí)將其設(shè)置為0
args=(data,mean_squared_error) 其中data就是你們讀取進(jìn)來(lái)的數(shù)據(jù), mean-squared_error就是一個(gè)軍方損失函數(shù),就是用前面的K-折交叉驗(yàn)證來(lái)求這一損失函數(shù)的最小值
method='TNC'就是模型訓(xùn)練的從而收斂的方法,其有很多選項(xiàng)如下大家可以多做實(shí)驗(yàn)從而得到一個(gè)最好損失結(jié)果,
- 'Nelder-Mead' :ref:`(see here) <optimize.minimize-neldermead>`
- 'Powell' :ref:`(see here) <optimize.minimize-powell>`
- 'CG' :ref:`(see here) <optimize.minimize-cg>`
- 'BFGS' :ref:`(see here) <optimize.minimize-bfgs>`
- 'Newton-CG' :ref:`(see here) <optimize.minimize-newtoncg>`
- 'L-BFGS-B' :ref:`(see here) <optimize.minimize-lbfgsb>`
- 'TNC' :ref:`(see here) <optimize.minimize-tnc>`
- 'COBYLA' :ref:`(see here) <optimize.minimize-cobyla>`
- 'SLSQP' :ref:`(see here) <optimize.minimize-slsqp>`
- 'trust-constr':ref:`(see here) <optimize.minimize-trustconstr>`
- 'dogleg' :ref:`(see here) <optimize.minimize-dogleg>`
- 'trust-ncg' :ref:`(see here) <optimize.minimize-trustncg>`
- 'trust-exact' :ref:`(see here) <optimize.minimize-trustexact>`
- 'trust-krylov' :ref:`(see here) <optimize.minimize-trustkrylov>`
每一個(gè)方法都不一樣,不同的數(shù)據(jù)也可能適合不同的方法大家可以多嘗試嘗試,?
bounds就是限制α、β和γ的范圍其通常都是位于0-1之間的一個(gè)數(shù)字,我們限制其一下不要讓其超出范圍!
opt = minimize(timeseriesCVscore, x0=[0, 0, 0],
args=(data, mean_squared_error,),
method="TNC", bounds=((0, 1), (0, 1), (0, 1))
)
之后的代碼就是將我們訓(xùn)練好的三個(gè)參數(shù)α、β和γ取出來(lái)
alpha, beta, gamma = opt.x
?下面的代碼就是正式到我們預(yù)測(cè)的部分了,其中的大部分參數(shù)我們都已經(jīng)講過(guò)了,除了其中的scaling_factor大家可以將其理解為一個(gè)平滑的參數(shù),之后就是我們對(duì)輸出結(jié)果作了一個(gè)三指數(shù)的平滑操作可以讓數(shù)據(jù)更加平滑從而提高精度!??!
model = HoltWinters(data, slen=cycle,
alpha=alpha,
beta=beta,
gamma=gamma,
n_preds=pre_len, scaling_factor=2)
model.triple_exponential_smoothing()
最后我們打印一下結(jié)果即可
print(model.result)
?
?
開(kāi)始訓(xùn)練
將上述準(zhǔn)備工作全部做完以后我們就可以運(yùn)行我們的程序開(kāi)始訓(xùn)練了!
運(yùn)行你們保存代碼的文件,控制臺(tái)就會(huì)輸出訓(xùn)練過(guò)程
?我這里選用的method是L-BFGS-B這個(gè)對(duì)于我的數(shù)據(jù)而言我能拿到更高的精度,其控制臺(tái)輸出如上圖所示,直到其最終收斂!
可以看到控制臺(tái)收斂以后打印出了?α、β和γ三個(gè)參數(shù),其中α=0.38537304、β=0和γ=0.89117814
α表示對(duì)當(dāng)前觀測(cè)值的加權(quán)系數(shù),β表示對(duì)趨勢(shì)的加權(quán)系數(shù),γ表示對(duì)季節(jié)性的加權(quán)系數(shù)。
?
預(yù)測(cè)結(jié)果
我將所有的結(jié)果輸出下來(lái)并進(jìn)行了保存到本地的csv文件中并用excel畫出了如圖可以看出預(yù)測(cè)值和真實(shí)值之間的誤差還是有一定誤差的!
這個(gè)圖可以看出我們的誤差MAE大部分都集中在0-0.1之間預(yù)測(cè)效果還是可以的!
到此Holt-Winters模型的使用就講解完了?。。。。∠M蠹叶寄苓\(yùn)行出一個(gè)好的結(jié)果!?
其它時(shí)間序列預(yù)測(cè)模型講解
后期我會(huì)講一些最新的預(yù)測(cè)模型包括transform, Informer,TPA-LSTM,ARIMA,XGBOOST,Holt-winter,移動(dòng)平均法等等一系列關(guān)于時(shí)間序列預(yù)測(cè)的模型,包括深度學(xué)習(xí)和機(jī)器學(xué)習(xí)方向的模型我都會(huì)講,你可以根據(jù)需求選取適合你自己的模型進(jìn)行預(yù)測(cè),如果有需要可以+個(gè)關(guān)注,包括本次模型我自己的代碼和數(shù)據(jù)大家有需要我也會(huì)放出百度網(wǎng)盤下載鏈接?。?/strong>
-----------------------------------------------------MTS-Mixers------------------------------------------------------------
【全網(wǎng)首發(fā)】(MTS-Mixers)(Python)(Pytorch)最新由華為發(fā)布的時(shí)間序列預(yù)測(cè)模型實(shí)戰(zhàn)案例(一)(包括代碼講解)實(shí)現(xiàn)企業(yè)級(jí)預(yù)測(cè)精度包括官方代碼BUG修復(fù)Transform模型
--------------------------------------------------------LSTM-----------------------------------------------------------------
?時(shí)間序列預(yù)測(cè)模型實(shí)戰(zhàn)案例(三)(LSTM)(Python)(深度學(xué)習(xí))時(shí)間序列預(yù)測(cè)(包括運(yùn)行代碼以及代碼講解)
如果大家有不懂的也可以評(píng)論區(qū)留言一些報(bào)錯(cuò)什么的大家可以討論討論看到我也會(huì)給大家解答如何解決!
?文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-751784.html
?
到了這里,關(guān)于時(shí)間序列預(yù)測(cè)模型實(shí)戰(zhàn)案例(二)(Holt-Winter)(Python)結(jié)合K-折交叉驗(yàn)證進(jìn)行時(shí)間序列預(yù)測(cè)實(shí)現(xiàn)企業(yè)級(jí)預(yù)測(cè)精度(包括運(yùn)行代碼以及代碼講解)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!