Python 時(shí)間序列預(yù)測(cè):Hot-Winters
本文轉(zhuǎn)載自微信公眾號(hào)「Python中文社區(qū)」,作者wedo實(shí)驗(yàn)君。轉(zhuǎn)載本文請(qǐng)聯(lián)系Python中文社區(qū)公眾號(hào)。
1. 什么是Holt-Winters
時(shí)間序列是非常常見的數(shù)據(jù)格式,以[時(shí)間,觀測(cè)值]形式表現(xiàn),如下圖。
現(xiàn)實(shí)場(chǎng)景中如股票走勢(shì)圖,國(guó)家GDP歷年數(shù)據(jù),機(jī)器cpu利用率,內(nèi)存數(shù)據(jù)等都是時(shí)間序列。對(duì)未來(lái)時(shí)間的觀測(cè)值進(jìn)行預(yù)測(cè)是有意義的工作,提前預(yù)知未來(lái)的數(shù)據(jù)的走勢(shì),可以提前做出行動(dòng),如預(yù)測(cè)cpu使用率,如果cpu飆高,可以及早進(jìn)行調(diào)整,避免機(jī)器負(fù)載過(guò)高而宕機(jī),這個(gè)在AIOPS是很常見的一個(gè)應(yīng)用場(chǎng)景。
今天要說(shuō)到Holt-Winters是利用三次指數(shù)平滑來(lái)做時(shí)間序列預(yù)測(cè)的方法。Holt-Winters是綜合了1957年Holt和1960年Winters兩個(gè)人的思路的一種方法。
一次指數(shù)平滑
我們來(lái)看下,一次指數(shù)平滑如下圖:
可知,si表示第i時(shí)刻的平滑估計(jì),si可以表示為當(dāng)前實(shí)際值xi和上一時(shí)刻平滑估計(jì)值得加權(quán)組合,權(quán)重由alpha來(lái)決定。那為什么稱為指數(shù)平滑呢?我們來(lái)把式子展開,如下:
有點(diǎn)類似泰勒展開式的味道
alpha 屬于[0, 1], 越大表示近期的數(shù)據(jù)影響更大
二次指數(shù)平滑:加上趨勢(shì)的因素
一次指數(shù)平滑,沒(méi)有考慮時(shí)間序列的趨勢(shì)和季節(jié)性,二次指數(shù)平滑加上趨勢(shì)因素。
從公式可知,一個(gè)時(shí)間序列的時(shí)刻值分解為baseline部分和趨勢(shì)部分,t表示趨勢(shì),可以表示為連續(xù)兩個(gè)時(shí)刻的差值;可知,ti也是一次的指數(shù)平滑。
Holt-Winters三次指數(shù)平滑:加上季節(jié)性因素
在二次指數(shù)平滑基礎(chǔ)上,考慮季節(jié)性因素,就是三次指數(shù)平滑,也就是Holt-Winters。由此,一個(gè)時(shí)間序列的時(shí)刻值分解為baseline部分和趨勢(shì)部分以及季節(jié)部分。由于季節(jié)性,存在周期,比如按周,按月等。pi季節(jié)性為當(dāng)前季節(jié)性值和上一個(gè)周期季節(jié)性估計(jì)值的加權(quán)組合,周期在公式中以k來(lái)表示。如下:
2. Holt-Winters的實(shí)現(xiàn)
從第一部分可知,要實(shí)現(xiàn)Holt-Winters,只要知道:
- 初始值:s0,t0和p0
- 合適的參數(shù):alpha,beta, gamma
- 套入公式即可完成預(yù)測(cè)
三個(gè)重要參數(shù):alpha,beta, gamma都屬于[0, 1]之間,要么人為的搜索,要么通過(guò)數(shù)據(jù)來(lái)估計(jì),通常采用L-BFGS優(yōu)化算法來(lái)擬合數(shù)據(jù)。優(yōu)化算法來(lái)自包scipy.optimize的fmin_l_bfgs_b。
- from __future__ import division
- from sys importexit
- from math import sqrt
- from numpy import array
- from scipy.optimize import fmin_l_bfgs_b
- # 優(yōu)化算法的loss function,即判斷擬合效果,由RMSE MAE等
- def RMSE(params, *args):
- Y = args[0]
- type = args[1]
- rmse = 0
- alpha, beta, gamma = params
- m = args[2]
- a = [sum(Y[0:m]) / float(m)]
- b = [(sum(Y[m:2* m]) - sum(Y[0:m])) / m ** 2]
- if type == 'additive':
- s = [Y[i] - a[0] for i in range(m)]
- y = [a[0] + b[0] + s[0]]
- for i in range(len(Y)):
- a.append(alpha * (Y[i] - s[i]) + (1- alpha) * (a[i] + b[i]))
- b.append(beta * (a[i + 1] - a[i]) + (1- beta) * b[i])
- s.append(gamma * (Y[i] - a[i] - b[i]) + (1- gamma) * s[i])
- y.append(a[i + 1] + b[i + 1] + s[i + 1])
- rmse = sqrt(sum([(m - n) ** 2for m, n in zip(Y, y[:-1])]) / len(Y))
- return rmse
- # 加性的時(shí)間序列
- def additive(x, m, fc, alpha = None, beta = None, gamma = None):
- Y = x[:]
- # 利用fmin_l_bfgs_b來(lái)估計(jì)參數(shù)alpha beta和gamma
- if(alpha == Noneor beta == Noneor gamma == None):
- initial_values = array([0.3, 0.1, 0.1])
- boundaries = [(0, 1), (0, 1), (0, 1)]
- type = 'additive'
- parameters = fmin_l_bfgs_b(RMSE, x0 = initial_values, args = (Y, type, m), bounds = boundaries, approx_grad = True)
- alpha, beta, gamma = parameters[0]
- # 初始值 a表示baseline, b表示趨勢(shì),s表示季節(jié)性,y表示預(yù)測(cè)值, 分別取第一個(gè)周期的統(tǒng)計(jì)數(shù)據(jù)為初始值
- a = [sum(Y[0:m]) / float(m)]
- b = [(sum(Y[m:2* m]) - sum(Y[0:m])) / m ** 2]
- s = [Y[i] - a[0] for i in range(m)]
- y = [a[0] + b[0] + s[0]]
- rmse = 0
- # 套用上面公式,從0開始,fc表示預(yù)測(cè)的數(shù)量,如已知前7天,預(yù)測(cè)接下來(lái)的一個(gè)小時(shí)的數(shù)據(jù),如果數(shù)據(jù)粒度是5分鐘,fc為12。
- for i in range(len(Y) + fc):
- if i == len(Y):
- # 預(yù)測(cè)值為
- Y.append(a[-1] + b[-1] + s[-m])
- a.append(alpha * (Y[i] - s[i]) + (1- alpha) * (a[i] + b[i]))
- b.append(beta * (a[i + 1] - a[i]) + (1- beta) * b[i])
- s.append(gamma * (Y[i] - a[i] - b[i]) + (1- gamma) * s[i])
- y.append(a[i + 1] + b[i + 1] + s[i + 1])
- # 計(jì)算rmse值
- rmse = sqrt(sum([(m - n) ** 2for m, n in zip(Y[:-fc], y[:-fc - 1])]) / len(Y[:-fc]))
- return y[-fc:], alpha, beta, gamma, rmse
另外,statsmodels包中也提供的實(shí)現(xiàn)的方法
- from statsmodels.tsa.holtwinters importExponentialSmoothing
3. Holt-Winters參數(shù)
從上面實(shí)現(xiàn)可知,holt-winters通過(guò)預(yù)估alpha,beta和gamma來(lái)預(yù)測(cè)。算法的關(guān)鍵就是這三個(gè)參數(shù)和初始化值。三個(gè)參數(shù)可以通過(guò)優(yōu)化算法來(lái)預(yù)估,但有可能并不是最優(yōu)的。初始值的設(shè)置除了上面統(tǒng)計(jì)值外,還可以通過(guò)時(shí)序的分解的趨勢(shì)和季節(jié)部分來(lái)初始。
- import numpy as np
- from pandas import read_csv
- import matplotlib.pyplot as plt
- from statsmodels.tsa.seasonal import seasonal_decompose
- decomposition = seasonal_decompose(df_clean.bw, model='additive', period=288)
- decomposition.plot()
Holt-Winters針對(duì)波形比較穩(wěn)定,沒(méi)有突刺的情況下,效果會(huì)比較好。
對(duì)于存在突刺,統(tǒng)一的alpha,beta,gamma不能很好擬合,預(yù)測(cè)可能會(huì)滯后。
4. 總結(jié)
本文分享了時(shí)間序列預(yù)測(cè)算法Holt-Winters以及重要參數(shù)的選擇,希望對(duì)你有幫助??偨Y(jié)如下:
- Holt-Winters是三次指數(shù)平滑,分別為baseline,趨勢(shì)和季節(jié)性;
- alpha、beta和gamma分別為baseline,趨勢(shì)和季節(jié)性的指數(shù)加權(quán)參數(shù),一般通過(guò)優(yōu)化算法L-BFGS估計(jì)
- 初始化可通過(guò)平均值,也可通過(guò)時(shí)間序列分解得到
- 周期m或者k的選擇要根據(jù)實(shí)際數(shù)據(jù)來(lái)選擇
- Holt-Winters針對(duì)波形比較穩(wěn)定,沒(méi)有突刺的情況下,效果會(huì)比較好
作者簡(jiǎn)介:wedo實(shí)驗(yàn)君, 數(shù)據(jù)分析師;熱愛生活,熱愛寫作