04.12.3
Holt-Winters
ExponentialSmoothing(trend="additive", seasonal="add", seasonal_periods=12) の 3 つの 33 か月予測を 1 枚に重ねます。SES の水平線、Holt の直線に対し、Holt-Winters の予測だけが冬 3300 超・夏 2100 前後の山谷をたどることが図で分かります。Holtの線形指数平滑法 で水準と傾きを \(\alpha\)・\(\beta\) で更新する流れを先に見ておくと、Holt-Winters 法はそこに季節値 12 個を \(\gamma\) で更新する処理を足しただけだと分かります。
直感 #
天然ガス消費量は毎年 1 月に 3000 BCF を超え、7〜8 月に 2000 前後へ落ちる 12 か月周期を持ちます。Holt 法はこの系列を「水準 + 傾き」の直線で表すので、冬と夏の差 1000 BCF がすべて誤差になります。Holt-Winters 法は「1 月はいつも水準より +600、7 月は −300」といった月ごとのズレを 12 個の季節値 \(s_t\) として覚え、予測ではその月の季節値を直線に足し戻します。季節値の更新は \(s_t = \gamma(y_t - \ell_{t-1} - b_{t-1}) + (1 - \gamma) s_{t-m}\) で、12 か月前の同じ月の季節値を \(\gamma\) の重みで最新の観測に寄せる、という SES と同じ形です。加法季節(seasonal="add")は山谷の高さが年によらず一定とみなし、乗法季節(seasonal="mul")は水準に比例して山谷も大きくなるとみなします。
1. ライブラリ #
| |
何が起きているか(ステップで見る) #
コードを読む前に、この手法が図の上で何をしているかを追ってみましょう。「再生」を押すか、スライダーを動かすと 1 手順ずつ進みます。
見るポイント:水準 → 傾き → 季節 と要素を足すほど、未来への伸ばし方が豊かになる。
サンプルデータ #
Natural Gas Consumption (NATURALGAS) の月次データを使います。数値の単位は BCF(10 億立方フィート)で、2013 年 1 月から 2022 年 9 月までの 117 か月分を辞書で埋め込み、月初の等間隔 index を持つ DataFrame に整えます。
| |
| Natural Gas Consumption(BCF) | |
|---|---|
| 2013-01-01 | 2878.8 |
| 2013-02-01 | 2567.2 |
| 2013-03-01 | 2521.1 |
| 2013-04-01 | 1967.5 |
| 2013-05-01 | 1752.5 |
全期間を描くと、1 月の山(2900 → 3600 BCF)と 7〜8 月の谷(1900 → 2600 BCF)が 12 か月周期で繰り返し、山も谷も 10 年でゆっくり上がっています。山と谷の差は 1000 前後でほぼ一定なので、加法季節が合いそうだと予想できます。
| |

データの分割 #
データの末尾(2020 年 1 月以降の 33 か月)を予測性能の検証に使い、2013〜2019 年の 84 か月(7 周期分)で学習します。
| |

モデルの学習と予測 #
statsmodels.tsa.holtwinters.ExponentialSmoothing のドキュメントを見ながら、trend と seasonal と seasonal_periods を指定します。SES と Holt は前のページと同じ係数で固定し、Holt-Winters は \(\alpha, \beta, \gamma\) を最尤推定に任せます。
| |
| |

実行結果の読み方 #
SES の予測は 2400 BCF 前後の水平線、Holt の予測はそこから緩やかに上がる直線で、どちらも検証データの冬の山(3300〜3600)と夏の谷(2100〜2300)を外します。Holt-Winters の丸マーカーの列だけが、2020 年 1 月・2021 年 1 月・2022 年 1 月に山、各年の夏に谷を作り、検証データの一点鎖線に沿って動きます。山の高さが実測より少し低めに出るなら、加法季節では 10 年で広がった山谷の振幅を表しきれていない兆候で、seasonal="mul" に変えて比べる価値があります。hw.params を表示すると推定された smoothing_level・smoothing_trend・smoothing_seasonal が見られ、hw.fittedvalues で学習期間内の当てはめ線を描くと季節値が 7 周期でどう安定していったかが分かります。
使いどころと落とし穴 #
Holt-Winters 法が向くのは、天然ガス消費量・電力需要・小売売上のように、はっきりした周期(月次なら 12、日次なら 7)とゆるやかなトレンドを持つ系列です。最初の落とし穴は加法と乗法の選び間違いで、山谷の差が水準に比例して広がるデータに seasonal="add" を使うと、遠い未来の山ほど低く予測されます。全期間の図で山と谷の差(約 1000 BCF)が一定か広がるかを先に見て決めます。二つ目は seasonal_periods の誤りで、月次に 4 や日次に 30 を渡しても statsmodels はエラーを出さずに学習するため、予測の山谷が実測とずれる形でしか気づけません。三つ目はデータの短さで、季節値 12 個を推定するには最低 2 周期(24 か月)が必要で、1 年分では fit が失敗するか季節値が観測そのものを丸写しした形になります。季節性が 2 つ重なる日次データ(週次 7 と年次 365)は 1 つの seasonal_periods では表せないので、複数季節性のベンチマーク で扱う SARIMAX + フーリエ項などに切り替えます。
- Holtの線形指数平滑法 — SESにトレンド成分を加えた拡張
- ホルト・ウィンター法 — 状態空間モデルとして Holt-Winters を定式化し予測区間まで出す
- ETS モデル — 誤差・トレンド・季節性を分離して予測