論文一覧に戻る 📚 用語解説(ジャストインタイム型データサイエンス教育)
指数平滑法
Exponential Smoothing
過去の値を「直近ほど重く・遠いほど軽く」加重平均する時系列予測。Holt法はトレンドにも対応。
時系列指数平滑Holt法

🔖 キーワード索引 — 拡張版

指数平滑法(Exponential Smoothing)に関連する用語を、 モデル・パラメータ・状態空間表現 別に索引化します。

カテゴリキーワード(日本語)キーワード(英語)
基本モデル単純指数平滑、 ホルト法(二重平滑)、 ホルト・ウィンタース法(三重平滑)SES, Holt's, Holt-Winters, ETS
パラメータ平滑化係数(α、 β、 γ)、 減衰係数(φ)、 季節周期alpha, beta, gamma, phi, seasonal period
構成要素水準(level)、 トレンド、 季節成分、 残差level, trend, seasonal, residual
関連モデルARIMA、 SARIMA、 状態空間モデル、 ProphetARIMA, SARIMA, state space, Prophet, DLM
評価指標MAE、 RMSE、 MAPE、 MASE、 AIC、 BICMAE, RMSE, MAPE, MASE, AIC, BIC
実装statsmodels、 prophet、 sktime、 pmdarima、 dartsstatsmodels.tsa, prophet, sktime, darts

💡 30秒で分かる結論

🍰 まずはやさしく

最近のデータを重視する予測方法です。

未来の値を予想するために使います。

スマホの利用時間の変化を予測します。

この手法の基本と使い方を学びます。

📖 包括的解説 — この概念を完全マスター

📍 学習の3ステップ

  1. 定義を理解する:この概念は何か? 数式や条件を確認
  2. 具体例を見る:実データ(SSDSE 等)で計算してみる
  3. 応用する:自分のデータに適用、 結果を解釈

🔧 Python実装パターン

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) 北海道 5,092,000 東京都 14,086,000 沖縄県 1,468,000 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 基本パターン
import pandas as pd
import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
import seaborn as sns

# データ読み込み
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', header=1)

df = df[df['地域コード'].astype(str).str.match(r'^R\d{5}$', na=False)].copy()
df['年度'] = pd.to_numeric(df['年度'], errors='coerce')
df['年'] = df['年度']
df['A1101'] = pd.to_numeric(df['総人口'], errors='coerce')
df['消費支出_東京'] = pd.to_numeric(df['消費支出(二人以上の世帯)'], errors='coerce')

# 基本統計量
df.describe()

# 可視化
sns.pairplot(df[['食料費(二人以上の世帯)', '教育費(二人以上の世帯)', '住居費(二人以上の世帯)']])
plt.show()

📚 統計概念マップでの位置

このページの上にある3つの概念マップ(関係マップ、 包含マップ、 ツリーマップ)でこの概念の位置づけが視覚的に分かります。 SES → Holt 線形 → Holt-Winters → ETS state-space → ARIMA との比較という発展線上に位置し、 平滑化係数 α・β・γ の意味、 状態空間表現、 予測区間の構築、 自動 ETS 選択 (Hyndman & Khandakar 2008) と結びつけると指数平滑法の役割が立体的に見えてきます。

🎯 指数平滑法を SSDSE-B-2026 で活かす実践テーマ

💡 指数平滑法でよく使うコマンド集

機能 Python (statsmodels) 補足
SES 当てはめSimpleExpSmoothing(y).fit()α は自動最適化、 .params['smoothing_level']
Holt 線形Holt(y).fit()α, β を同時推定、 トレンドを追加
Damped HoltHolt(y, damped_trend=True).fit()φ < 1 で長期発散を抑止
Holt-WintersExponentialSmoothing(y, trend='add', seasonal='add', seasonal_periods=12).fit()加法的季節性 12 ヶ月周期
ETS 自動選択ETSModel(y).fit()AIC で error/trend/seasonal を選定
予測区間res.get_prediction(...).summary_frame()状態空間 ETS のみ正規分布 CI 出力
残差自己相関acorr_ljungbox(res.resid, lags=10)Ljung-Box: 白色雑音か検定

🚧 指数平滑法に固有の落とし穴と対策

📊 指数平滑法の結果報告フォーマット

🌐 指数平滑法の応用分野

🎓 指数平滑法を深掘りする文献

🔗 指数平滑法と関連時系列概念の地図

指数平滑法は 3 つの軸で位置づけられます: (1) 状態空間モデルの一族として ARIMA/Kalman フィルタと等価、 (2) 指数加重移動平均 (EWMA) の予測版として品質管理図と共通の数学、 (3) 自動予測フレームワークとして Prophet / NeuralProphet / DeepAR と並列。

指数平滑法を取り巻く時系列用語グループ

グループ 主要概念
平滑化族SES, Holt 線形, Damped Holt, Holt-Winters 加法/乗法, EWMA
状態空間 ETSETS(A,A,A), ETS(M,A,M), 予測区間, 自動選択 (AIC)
時系列分解STL, X-13ARIMA-SEATS, 季節調整, トレンド抽出
並列モデルARIMA, SARIMA, SARIMAX, VAR, TBATS, Prophet
機械学習系XGBoost (lag特徴), LSTM, NeuralProphet, DeepAR
評価指標RMSE, MAE, MAPE, sMAPE, MASE, AIC/AICc
残差診断Ljung-Box, ACF, PACF, QQ plot, Jarque-Bera
構造変化介入変数, CUSUM, change point detection, COVID 効果
予測区間正規分布 CI, 経験ブートストラップ, 量子回帰 CI
運用ローリング再学習, walk-forward CV, 1-step / h-step 予測
パラメータ最適化最尤推定, SSE 最小化, Box-Cox 変換
複数季節TBATS, MSTL, Fourier 項追加

指数平滑法の学習順序

  1. 移動平均 (SMA, WMA) と EWMA の重み構造を比較
  2. SES の漸化式 ℓ_t = α y_t + (1-α) ℓ_{t-1} を手計算で 5 期分回す
  3. α の最適化を SSE 最小化で実装、 statsmodels の自動結果と照合
  4. Holt 線形でトレンド項 b_t を追加、 切片+傾きの 2 状態を可視化
  5. Damped Holt で φ の役割と長期予測の収束先を確認
  6. Holt-Winters 加法/乗法の使い分け (振幅一定 vs レベル比例)
  7. 状態空間 ETS で予測区間を AIC 自動選択モデルから算出
  8. ETS vs ARIMA の RMSE 比較を walk-forward CV で実施
  9. Damped Holt + 介入変数で COVID-19 ショックに対応する応用

📝 指数平滑法の実践練習 — SSDSE-B-2026 で挑戦

初級課題

  1. 東京都の総人口 10 年 (2014-2023) に SES を当て、 α と 2024 年予測値を求める
  2. 同じ系列に Holt 線形を当て、 トレンド傾き b_T と 3 年先予測を計算
  3. α=0.3, 0.5, 0.8 で SES を回し、 RMSE が最小の α を見つける
  4. SES の予測値と単純移動平均 (window=3) の予測値を同一プロットで比較

中級課題

  1. 47 都道府県すべての人口にバッチで Holt 線形を当て、 2030 年予測値を地図プロット
  2. Damped Holt (φ=0.95) で東京都 2030 年予測を Holt 線形と比較、 発散度合いを評価
  3. 家計食料費 (10 年) で SES と Holt の AIC を比較、 適切なモデルを選定
  4. walk-forward CV (origin から 1 期ずつ予測) で SES の RMSE を算出

上級課題

  1. statsmodels ETSModel で error/trend/seasonal の 8 通りを自動選択、 AIC 最小モデルを採用
  2. COVID-19 期間 (2020-2021) に介入変数を入れて Damped Holt を再推定、 予測精度を比較
  3. 同じ系列に ARIMA(0,1,1) と SES の数学的等価性を確認 (Hyndman 教科書 8.10)
  4. Prophet (changepoint_prior_scale=0.05) と Holt-Winters の RMSE/MAPE を SSDSE 月次系列で比較

📍 あなたが今見ているもの

🍰 まずはやさしく

データの流れを読むための道具です。

正しい分析の手順を知るために使います。

都道府県の人口の変化を調べます。

定義から実装までの流れを読みます。

論文中に 「指数平滑法」として登場する用語。

指数平滑法 とは:過去の値を「直近ほど重く・遠いほど軽く」加重平均する時系列予測。Holt法はトレンドにも対応。

本ページでは「exponential smoothing」を扱う。 統計データ分析コンペティション (2026) の教材で、 SSDSE-B-2026 (47 都道府県 × 複数年 × 100 超列) の実データを使った再現可能な学習を目指す。

「exponential smoothing」は統計・データサイエンスの体系における重要概念のひとつ。 本ページは「定義・直感・数式・実装・落とし穴・関連手法」の 6 視点で構成され、 各視点は独立して読めるが順序通り読むと体系的な理解が得られる。

🎨 直感で掴む — 「直近を重く、 過去を軽く」を音で例える

🍰 まずはやさしく

音のエコーのような仕組みです。

直近の情報をどれだけ大切にするか決めます。

友達の最近の発言を重視する感覚です。

重みの変わり方をイメージで理解します。

指数平滑法を音で例えると、 **エコー(残響)** が分かりやすい。 部屋で手を 1 回叩くと、 直前の音は大きく聞こえ、 過去の反響音は徐々に小さくなる。 これと同じで、 直近の観測 $y_t$ は α の重みで強く効き、 1 期前の予測 $\hat y_{t|t-1}$ には $(1-\alpha)$ の重みで弱く効く。 過去 k 期前のデータの実効重みは $(1-\alpha)^k$ で **指数関数的に減衰**。 α=0.3 なら 5 期前のデータは元の重みの 17%、 10 期前は 3%、 20 期前は 0.1% にしか効かない。

別の比喩として **「最近の同僚の意見をどれだけ重視するか」** がある。 α=1 なら「直近の発言だけ聞く」(過去を全部忘れる)、 α=0 なら「最初の発言だけ聞いて以降を無視する」(更新しない)。 α=0.3 程度なら「直近 7-8 期分の意見を平均化」する感覚になる。 これが SES の本質。

Holt 法はこのエコーに「方向の感覚」を足したもの。 SES が「水位だけ」追跡するなら、 Holt は「水位+傾き(流れの強さ)」を追跡する。 Holt-Winters はさらに「四季の繰り返し」も追跡する。 これら 3 つを階層的に足し算する **3 層の指数加重移動平均** と理解すると、 数式の階段がスッと入ってくる。

視覚的には、 単純平均(SMA)が**真っ直ぐな滑り台**だとすると、 指数平滑は**カーブして直近に張り付くソリ**。 グラフ上では、 直近の急変動にすばやく追従しつつ、 過去のノイズは滑らかに丸める性質が見える。

🧪 SSDSE-B-2026 縦断データで指数平滑法を実装する

SSDSE-B-2026 は都道府県×年(2014-2023 の 10 年)の縦断データである。 指数平滑法の真価は時系列予測にあるので、 ここでは **東京都の総人口 10 年** を例に、 Simple Exponential Smoothing(SES)→ Holt 線形 → Holt-Winters まで段階的に当てはめる。

📥 入力データ: 東京都の総人口 (2014-2023)

SSDSE-B-2026 から東京都 (R13100) の A1101 総人口 を抽出する。 10 行 1 列の時系列ベクトルになる。

年度 総人口(千人) 2014 13399 2015 13515 2016 13646 2017 13768 2018 13887 2019 14007 2020 14048 2021 14010 2022 14038 2023 14086

🐍 Simple Exponential Smoothing(SES)— トレンドも季節性も無いとき

このコードでやること: statsmodels.tsa.holtwinters.SimpleExpSmoothing で SES を当てはめ、 α を尤度最大化で自動推定。 翌年予測を出す。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import pandas as pd
import numpy as np
from statsmodels.tsa.holtwinters import SimpleExpSmoothing

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', header=1)
df = df[df['地域コード'].astype(str).str.match(r'^R\d{5}$', na=False)].copy()
df['年度'] = pd.to_numeric(df['年度'], errors='coerce')
df['年'] = df['年度']
df['A1101'] = pd.to_numeric(df['総人口'], errors='coerce')
df['消費支出_東京'] = pd.to_numeric(df['消費支出(二人以上の世帯)'], errors='coerce')

tokyo = df[df['都道府県'] == '東京都'].sort_values('年度')
# 出力に「千人」と書くので、ここで千人に直しておく(A1101 の単位は「人」)。
# 直近 10 年ぶんだけを使う。
y = tokyo['A1101'].values[-10:] / 1000  # 総人口 10 年(千人)

ses = SimpleExpSmoothing(y, initialization_method='estimated').fit(optimized=True)
print(f"α (smoothing_level) = {ses.params['smoothing_level']:.4f}")
print(f"SSE = {ses.sse:.1f}")
print(f"次年予測 ŷ(2024) = {ses.forecast(1)[0]:.1f} 千人")

📤 実行例(東京都人口で実測した出力):

α (smoothing_level) = 1.0000 SSE = 80275.0 次年予測 ŷ(2024) = 14086.0 千人

💬 α=1.000 はちょうど「直近観測=次の予測」を意味する。 東京の人口は単調増加トレンドを持つので、 SES の「水準のみ追跡」モデルは尤度を最大化しようとすると α が上限 1 に張り付く。 翌年予測は「直近値そのまま」になり、 **トレンドを取り損ねている**。 → 次の Holt 線形へ。

🐍 Holt 線形トレンド法 — 増減トレンドを別パラメータで追跡

このコードでやること: Holt で水準 α とトレンド β を同時推定。 翌年・翌々年の 2 期先予測を出す。

1
2
3
4
5
6
7
8
from statsmodels.tsa.holtwinters import Holt

holt = Holt(y, initialization_method='estimated').fit(optimized=True)
print(f"α (level)  = {holt.params['smoothing_level']:.4f}")
print(f"β (trend)  = {holt.params['smoothing_trend']:.4f}")
print(f"AICc = {holt.aicc:.1f}")
fc = holt.forecast(2)
print(f"ŷ(2024) = {fc[0]:.1f} / ŷ(2025) = {fc[1]:.1f} 千人")

📤 実行例:

α (level) = 1.0000 β (trend) = 0.0000 AICc = 115.3 ŷ(2024) = 14162.3 / ŷ(2025) = 14238.7 千人

💬 α=1.000・β=0.000 と両係数が境界(上限 1/下限 0)に張り付いた。 水準は直近値をそのまま採用し、 トレンドは初期推定の傾き(約 +76 千人/年)で固定される。 2 期先予測は 14086 から +76.3・+76.4 とほぼ等間隔で線形外挿される。 ただし 2020-2021 にコロナで一時減少(14048→14010)したので、 単純線形外挿はやや楽観的。

📝 より正確な分析: 東京都人口 2014-2023 のような 短くほぼ単調増加の系列では、 statsmodels の最尤推定が平滑化係数を境界へ押しやる(SES・Holt とも α→1、 Holt の β→0)。 これは「直近値を最重視し、 トレンドは初期傾きで固定」する縮退解で、 中途半端な小数(かつて誤って α=0.6321=1−1/e などと記載していた値)は再現されない。 n=10 と短いこと、 系列に曲率がほとんど無いことが原因で、 実務では系列長を増やすか AICc でモデル比較して判断する。

🐍 減衰トレンド (Damped Trend) — 遠未来で発散しないように

このコードでやること: damped_trend=True で減衰係数 φ を導入し、 長期予測が無限に発散しないようにする。 φ<1 なら遠未来で水平線へ収束。

1
2
3
4
5
6
7
damped = Holt(y, damped_trend=True, initialization_method='estimated').fit(optimized=True)
print(f"α = {damped.params['smoothing_level']:.4f}")
print(f"β = {damped.params['smoothing_trend']:.4f}")
print(f"φ = {damped.params['damping_trend']:.4f}")
fc5 = damped.forecast(5)
for i, v in enumerate(fc5, 1):
    print(f"ŷ(202{3+i}) = {v:.1f}")

📤 実行例:

α = 1.0000 β = 0.0000 φ = 0.8277 ŷ(2024) = 14112.9 ŷ(2025) = 14135.2 ŷ(2026) = 14153.7 ŷ(2027) = 14169.0 ŷ(2028) = 14181.6

💬 φ=0.828 → 5 期先の増分は初期 +27 から +13 へ徐々に減衰。 「東京の人口は将来横ばいに向かう」というドメイン知識と整合的。 M4 コンペでは damped Holt が単純 Holt より平均 5-10% MASE が良かったことが報告されている。

🐍 SSDSE-B から 47 都道府県を一括予測してランキング

このコードでやること: 47 県すべてに damped Holt を当てはめ、 2024 年予測値を 2023 年実測と比較して「増加率トップ 5」を出す。

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) 北海道 5,092,000 東京都 14,086,000 沖縄県 1,468,000 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# ── 時系列の例で使うデータを用意します ──
import pandas as pd

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', header=1)
df = df[df['地域コード'].astype(str).str.match(r'^R\d{5}$', na=False)].copy()
df['年度'] = pd.to_numeric(df['年度'], errors='coerce')
df['年'] = df['年度']
for _c in ['総人口', '消費支出(二人以上の世帯)']:
    df[_c] = pd.to_numeric(df[_c], errors='coerce')
df['A1101'] = df['総人口']
df['消費支出_東京'] = df['消費支出(二人以上の世帯)']

results = []
for pref, g in df.groupby('都道府県'):
    g = g.sort_values('年度')
    y = g['A1101'].values
    if len(y) < 8: continue
    try:
        m = Holt(y, damped_trend=True, initialization_method='estimated').fit(optimized=True)
        pred = m.forecast(1)[0]
        results.append({'県': pref, '2023': y[-1], '2024予測': pred,
                        '増加率(%)': 100*(pred - y[-1])/y[-1]})
    except Exception:
        pass
out = pd.DataFrame(results).sort_values('増加率(%)', ascending=False).head(5)
print(out.to_string(index=False))

📤 実行例(典型出力、 ±数桁の誤差あり):

県 2023 2024予測 増加率(%) 東京都 14086 14128 0.30 沖縄県 1468 1468 -0.00 神奈川 9229 9226 -0.03 埼玉県 7331 7326 -0.07 滋賀県 1407 1406 -0.09

💬 増加率トップ 5 でも東京都しか明確な正の予測にならず、 沖縄・神奈川以下はほぼ横ばい〜微減。 全国的な人口減少局面で、 指数平滑法が「直近を重視」して各県の趨勢を素直に外挿した結果である。 damped Holt の当てはめは短系列だと最適化が不安定になりやすく、 statsmodels のバージョン差で下位順位が入れ替わりうる点にも注意。

🎨 概念図で押さえる(指数平滑法を視覚で理解)

指数平滑法は「最新ほど重く、 過去ほど軽く」重みづけて移動平均を取る予測手法です。 以下 3 点の概念図で「α の効果」「3 階層(水準・トレンド・季節)」「ETS 系の使い分け」を視覚的に整理します。

図A: 平滑化係数 α — 過去重みの指数減衰

重み w_k = α(1-α)^k α=0.2 (滑らか・遅い反応) 過去 10 期で 89% カバー α=0.8 (機敏・最新値重視) 直近 1-2 期でほぼ完結

→ 平滑化係数 α は「現在値をどれだけ重視するか」のダイヤルです。 α が小さい(0.1-0.3)と過去多数の値が均等に効くため滑らかな予測になる代わりに変化への反応が遅れます。 α が大きい(0.7-0.9)と最新値ほぼそのものになり、 ノイズも追従してしまいます。 多くの場合 α は MSE 最小化で 0.05-0.4 程度に自動推定されます。

図B: 3 階層分解 — 水準・トレンド・季節

Holt-Winters: L_t + T_t + S_t = ŷ_t 水準 L_t α で平滑化 + トレンド T_t β で平滑化 + 季節 S_t (周期 12) γ で平滑化 = ŷ_{t+h} = L_t + h·T_t + S_{t-m+h}

→ Holt-Winters 法は時系列を「水準(L)+ トレンド(T)+ 季節(S)」の 3 成分に分解し、 それぞれを α, β, γ の 3 つの平滑化係数で別々に更新します。 月次の小売売上、 電力需要、 観光客数など、 トレンドと季節性を併せ持つデータの予測に強く、 ARIMA より実装が単純で実務で広く使われます。

図C: ETS 系統樹 — 使い分けの全体像

Hyndman ETS フレームワーク 時系列の特徴は? 水準のみ / トレンド / 季節 SES 単純指数平滑 水準のみ Holt 線形 水準 + トレンド damped 推奨 Holt-Winters 水準 + T + 季節 乗法/加法 統一表記 ETS(Error, Trend, Seasonal) — 例: ETS(A,A,A), ETS(M,Ad,M) A=加法, M=乗法, N=なし, d=damped — 自動選択は AIC 最小化

→ ETS フレームワークは「Error × Trend × Seasonal」の 3 軸で 30 種類のモデルを定義し、 AIC 最小化で自動選択します。 SES(水準のみ)→ Holt(+トレンド)→ Holt-Winters(+季節)と複雑さが増します。 トレンドが長期的に減衰する場合は damped Holt が頑健で、 M4 コンペでも上位常連。 季節性が比例的に変化するなら乗法(M)、 一定なら加法(A)を選びます。

🎨 概念図で押さえる

指数平滑法は時系列データの平滑化・予測に使われる。 時系列の典型形状、 自己相関、 残差プロットを順に確認する。

時系列データの典型形状(トレンド・季節・残差)
時系列は「トレンド + 季節 + 残差」に分解される。 ETS はこの 3 要素をパラメトリックにモデリング。
自己相関 ACF プロット
自己相関 ACF を確認すると季節性のラグ(例: 12 か月)が顕在化。 平滑化パラメータ調整の指針。
残差プロット(モデル評価)
残差にパターンが残っていれば、 モデルが捉えきれていない構造(季節・トレンド)がある証拠。

→ 予測モデル選択の順序は「時系列形状の確認 → ACF/PACF で構造把握 → 残差で適合度検証」。 指数平滑法はこの 3 段階すべてに直結する。

✅ 理解度チェック

  1. SES(単純指数平滑)の平滑化パラメータ α が大きいと、 何が起きるか?
  2. Holt 法と Holt-Winters 法の違いは何か?
  3. 加法的季節性と乗法的季節性、 どのようなデータで使い分けるか?
  4. ARIMA と指数平滑法の本質的な差を 1 行で述べよ。
  5. damped trend が必要になる場面の例を 1 つ挙げよ。

→ 全項目に答えられれば、 M4 系コンペでも適切なモデル選択ができる。

📐 数式と理論を深く読み解く — SES から状態空間表現まで

🍰 まずはやさしく

計算式で表した予測のルールです。

正確な予測値を出すために使います。

部活のスコアの変化を数式にします。

予測を導くための計算式を読み解きます。

指数平滑法は単なるヒューリスティックではなく、 **線形ガウス状態空間モデル(ETS)** として確率的に基礎付けられている。 ここでは数式を 4 段階で読み解く。

🔬 Step 1: 数式を言葉で読み解く — SES の漸化式

$$\hat y_{t+1|t} = \alpha y_t + (1-\alpha)\hat y_{t|t-1}$$

再帰展開すると $\hat y_{t+1|t} = \alpha\sum_{k=0}^{t-1}(1-\alpha)^k y_{t-k} + (1-\alpha)^t \hat y_{1|0}$。 過去の重みが **(1-α)^k で指数的に減衰** することがここから見える。

🔬 Step 2: 数式を言葉で読み解く — Holt 線形(水準+トレンド)

水準方程式と傾き方程式の連立で書ける: $$\ell_t = \alpha y_t + (1-\alpha)(\ell_{t-1} + b_{t-1})$$ $$b_t = \beta(\ell_t - \ell_{t-1}) + (1-\beta) b_{t-1}$$ $$\hat y_{t+h|t} = \ell_t + h \cdot b_t$$

上式は「水準は新観測と前期予測の重み付き平均」、 中式は「トレンドは水準差と前期トレンドの重み付き平均」、 下式は「h 期先予測 = 水準 + h × トレンド」。 β が大きいほど傾きが急変化する。

🔬 Step 3: 数式を言葉で読み解く — Holt-Winters(加法季節性)

$$\ell_t = \alpha(y_t - s_{t-m}) + (1-\alpha)(\ell_{t-1} + b_{t-1})$$ $$b_t = \beta(\ell_t - \ell_{t-1}) + (1-\beta) b_{t-1}$$ $$s_t = \gamma(y_t - \ell_{t-1} - b_{t-1}) + (1-\gamma) s_{t-m}$$ $$\hat y_{t+h|t} = \ell_t + h b_t + s_{t-m+h_m^+}$$

$m$ は季節周期(月次なら 12、 四半期なら 4)。 $s_{t-m}$ は **1 周期前の同期の季節成分**。 γ は季節成分の更新速度。 乗法版なら除算・乗算に置き換わる。 SSDSE は年次なので m=1 の場合は季節性なしと同義になり、 月次の家計調査などで m=12 と組む。

🔬 Step 4: 数式を言葉で読み解く — 状態空間 (ETS) 表現

Hyndman ら(2008)は指数平滑法を **ETS(E, T, S)** 状態空間で統一した。 E(Error: A/M)×T(Trend: N/A/Ad)×S(Season: N/A/M)の 30 通り。 $$y_t = w(\mathbf{x}_{t-1}) + r(\mathbf{x}_{t-1})\varepsilon_t$$ $$\mathbf{x}_t = f(\mathbf{x}_{t-1}) + g(\mathbf{x}_{t-1})\varepsilon_t$$

1 つの誤差項 $\varepsilon_t \sim \mathcal{N}(0,\sigma^2)$ が観測式・状態遷移式の両方を駆動する **single source of error (SSOE)** が特徴。 AICc で 30 通りから自動選択するのが statsmodels.tsa.exponential_smoothing.ETSModel や R の forecast::ets()

🔬 数式を言葉で読み解く

前節の SES / Holt / Holt-Winters / ETS で登場した記号を、 1 つずつ「読み方 → 意味 → 直感例」に分解する。 数式を頭から終わりまで「日本語に翻訳して音読」できるようになることがゴール。

① SES(単純指数平滑)の記号

記号 読み方 意味 具体例(家計消費月次)
$y_t$ワイ ティー時刻 $t$ の実測値2024 年 3 月の消費支出 = 340 千円
$\hat y_{t+1|t}$ワイハット ティープラスワン バー ティー時刻 $t$ までの情報で作る $t+1$ の 1 期先予測3 月までを見て予測した 4 月の消費
$\alpha$アルファ平滑化定数 $\in [0,1]$。 新観測の重み$\alpha=0.3$ → 新観測を 3 割、 過去を 7 割信頼
$(1-\alpha)^k$イチマイナスアルファのケー乗$k$ 期前の観測値の重み(指数減衰)$\alpha=0.3$ なら 1 期前 0.7、 2 期前 0.49、 …

② Holt 線形(水準+トレンド)の記号

記号 読み方 意味 数値イメージ
$\ell_t$エル ティー時刻 $t$ の水準(level)。 トレンドを除いた「いまの基準値」人口 1300 万人など、 系列の現在位置
$b_t$ビー ティー時刻 $t$ のトレンド(1 期あたりの増減)$b_t = +2.5$ → 月あたり 2.5 千人増
$\beta$ベータトレンドの平滑化定数 $\in [0,1]$$\beta$ 大 → 傾きが急変化(直近重視)
$\hat y_{t+h|t}$ワイハット ティープラスエイチ バー ティー$h$ 期先予測 $= \ell_t + h\cdot b_t$3 期先 = 現水準 + 3×トレンド

③ Holt-Winters(季節成分つき)の追加記号

記号 読み方 意味 月次データの例
$s_t$エス ティー時刻 $t$ の季節成分(周期的なズレ)12 月の消費はベースより +30 千円
$m$エム季節周期長月次なら $m=12$、 四半期なら $m=4$
$s_{t-m}$エス ティーマイナスエム1 周期前の同期の季節成分今年 12 月の予測に、 昨年 12 月の $s$ を流用
$\gamma$ガンマ季節成分の平滑化定数 $\in [0,1]$$\gamma$ 大 → 季節パターンを年ごとに更新

④ ETS(E, T, S) 状態空間表現の記号

略号 展開 選択肢 意味
EErrorA / M誤差の加法 (Additive) か乗法 (Multiplicative) か
TTrendN / A / Adなし / 線形 / 減衰トレンド
SSeasonN / A / Mなし / 加法季節性 / 乗法季節性

まとめると、 「$\alpha, \beta, \gamma$ は新観測をどの程度信頼するかの 3 ダイヤル」「$\ell_t, b_t, s_t$ は系列を分解した 3 つの内部状態」「$\hat y_{t+h|t}$ はその状態を時間方向に外挿した予測値」と読めば、 SES から ETS まで同じ枠組みで理解できる。

🧮 月次データの平滑化 — 合成データで実値計算

SSDSE-B-2026 は年度×都道府県のパネルで月次系列を含まないため、 ここでは月内の変動と平滑化の挙動を示す合成した月次消費支出(千円)12ヶ月分を用いて、 単純指数平滑を手計算で追います。

① 元データの月次推移

消費支出(千円)α=0.3 平滑値α=0.7 平滑値
1月320320.0320.0
2月285309.5295.5
3月340318.7326.7
4月295311.6304.5
5月310311.1308.4
12月410(年末増)355.2390.5

② 平滑化の漸化式

Sₜ = α · yₜ + (1 − α) · Sₜ₋₁
例:S₂ = 0.3 × 285 + 0.7 × 320 = 309.5(α=0.3 の場合)
S₂ = 0.7 × 285 + 0.3 × 320 = 295.5(α=0.7 の場合、 直近重視)

③ α の選び方

α = 0.1〜0.3:ノイズが多いデータ、 長期トレンド重視
α = 0.4〜0.6:中庸
α = 0.7〜0.9:直近データ重視、 急変動への追従
自動最適化は 最尤推定 または MSE 最小化

🧮 α 選択の手計算 — SSE 最小化と AICc の比較

α=0.1, 0.3, 0.5, 0.7, 0.9 を手計算でグリッド探索し、 SSE が最小になる α を確認する。 statsmodels の自動最適化結果と一致するかチェックする教育的演習。

🐍 SES の α グリッド探索を SSDSE 北海道人口で実装

このコードでやること: 北海道 (R01100) の総人口 2014-2023 に対して α を 0.05 刻みで動かし、 SSE を計算してプロット用データを作る。

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) 北海道 5,092,000 東京都 14,086,000 沖縄県 1,468,000 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# ── 時系列の例で使うデータを用意します ──
import pandas as pd

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', header=1)
df = df[df['地域コード'].astype(str).str.match(r'^R\d{5}$', na=False)].copy()
df['年度'] = pd.to_numeric(df['年度'], errors='coerce')
df['年'] = df['年度']
for _c in ['総人口', '消費支出(二人以上の世帯)']:
    df[_c] = pd.to_numeric(df[_c], errors='coerce')
df['A1101'] = df['総人口']
df['消費支出_東京'] = df['消費支出(二人以上の世帯)']

hokkaido = df[df['都道府県'] == '北海道'].sort_values('年度')
# SSE は単位の 2 乗で効くので、千人に直してから比べる(A1101 の単位は「人」)。
# 直近 10 年ぶんだけを使う。
y = hokkaido['A1101'].values[-10:] / 1000

def ses_sse(y, alpha):
    yhat = np.zeros_like(y, dtype=float)
    yhat[0] = y[0]
    for t in range(1, len(y)):
        yhat[t] = alpha * y[t-1] + (1 - alpha) * yhat[t-1]
    return np.sum((y[1:] - yhat[1:]) ** 2)

alphas = np.arange(0.05, 1.0, 0.05)
sses = [ses_sse(y, a) for a in alphas]
best_a = alphas[np.argmin(sses)]
print(f"最適 α = {best_a:.2f} (SSE = {min(sses):.0f})")
print(f"α=0.1 → SSE = {ses_sse(y, 0.1):.0f}")
print(f"α=0.5 → SSE = {ses_sse(y, 0.5):.0f}")
print(f"α=0.9 → SSE = {ses_sse(y, 0.9):.0f}")

📤 実行例(北海道人口で実測):

最適 α = 0.95 (SSE = 12738) α=0.1 → SSE = 178817 α=0.5 → SSE = 36266 α=0.9 → SSE = 13975

💬 北海道も α→1 に張り付く。 単調減少トレンド(人口減少県)でも SES では「直近をそのままコピー」が最適解になってしまう。 → これは「トレンドモデルへ進むべき」シグナル。 教科書の警告通り、 トレンドがある時系列に SES を当てるべきでないことが手計算で実感できる。

📊 表: 主要な指数平滑モデルとパラメータ・適用条件

モデルパラメータ適用条件SSDSE での例
SES (Simple)α のみ水準のみ、 トレンド・季節なし短期間の安定指標
Holt 線形α, β線形トレンドあり、 季節なし県別人口 10 年
減衰 Holtα, β, φトレンドが将来弱まる高齢化地域の人口推移
Holt-Winters 加法α, β, γ季節振幅が一定月次家計調査 (m=12)
Holt-Winters 乗法α, β, γ季節振幅が水準に比例月次小売販売額
ETS(M,Ad,M)α, β, γ, φ乗法誤差・減衰トレンド・乗法季節観光客数年内変動

🧮 補追: SSDSE-B-2026 で Holt-Winters seasonal と ETS auto を実行する

指数平滑法は (a) Simple ES (level のみ)(b) Holt (level + trend)(c) Holt-Winters (level + trend + seasonal) の 3 段階で拡張される。 statsmodels の ETSModel は誤差・トレンド・季節成分 (E,T,S) の各組合せを自動推定する。 SSDSE-B-2026 の年次データ (47 都道府県 × 複数年) を擬似月次系列に展開し、 Holt-Winters の挙動を確認する。

🎯 このコードでやること: SSDSE-B-2026 の東京都人口時系列 (5 年分の年次値を月次補間) に対し、 statsmodels ETSModel で誤差項 add/mul、 トレンド add、 季節 add の auto fit を行い、 AIC で最良モデルを選ぶ。

📥 入力データ (SSDSE-B-2026 抜粋、 東京都の年次人口を月次に補間):

SSDSE-B-2026 都道府県 年 A1101(総人口) R13000 東京都 2019 14007000 R13000 東京都 2020 14047594 R13000 東京都 2021 14010000 R13000 東京都 2022 14038000 R13000 東京都 2023 14086000
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# ── この抜粋で使うデータを用意します(東京都の年次系列。1 年度だけでは時系列にならない)──
# skiprows=[1] で 2 行目(日本語の項目名)を飛ばし、英字の項目コードを列名にする
import pandas as pd
from statsmodels.tsa.exponential_smoothing.ets import ETSModel

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
tokyo = df[df['Prefecture'] == '東京都'].sort_values('SSDSE-B-2026')
tokyo = tokyo[tokyo['SSDSE-B-2026'] >= 2019]        # 直近 5 年度
print(tokyo[['SSDSE-B-2026', 'A1101']].to_string(index=False))

ts = tokyo.set_index(pd.date_range('2019-01-01', periods=len(tokyo),
                                   freq='YS'))['A1101'].astype(float)

# ETS auto: 誤差 add, トレンド add, 季節なし (年次なので季節不要)
model = ETSModel(ts, error='add', trend='add', seasonal=None).fit(disp=False)
print('AIC =', round(model.aic, 2))
print('5 年先予測:')
print(model.forecast(5).round(0))

📤 実行例 (実際の出力):

AIC = 129.79 5 年先予測: 2024-01-01 14105843.0 2025-01-01 14130177.0 2026-01-01 14154511.0 2027-01-01 14178845.0 2028-01-01 14203179.0

💬 ETS(A,A,N) は AIC=129.79 で線形外挿予測を返す。 「数式を言葉で読み解く」と、 level l_t = α y_t + (1-α)(l_{t-1}+b_{t-1})、 trend b_t = β(l_t-l_{t-1}) + (1-β) b_{t-1} すなわち レベルは観測と前期予測の重み平均傾きはレベル差と前期傾きの重み平均。 年次データなので seasonal はオフだが、 月次家計調査なら seasonal='add' で 12 周期を学習させる。

🐍 補足: pmdarima.auto_arima との比較

Hyndman フレームワークでは ETS と ARIMA を AIC で比較し、 低い方を採用するのが標準。 pmdarima.auto_arima(ts, seasonal=True, m=12) で ARIMA 最良候補を取り、 上記 ETS と AIC 比較する。 一般に滑らかな単調系列は ETS、 自己相関構造が強い系列は ARIMA が有利。 M4 コンペ (2018) では damped Holt (ETS) が単体最強ベンチマーク、 上位は ETS+ARIMA ensemble。

🧮 数式に値を入れて手で計算する: 単純指数平滑法

合成データで α=0.3 の指数平滑値を計算する。

Step 1: データと初期値

x = [20, 25, 30, 28, 35] S₁ = x₁ = 20 (初期化) α = 0.3

Step 2: 更新

S_t = α·x_t + (1-α)·S_{t-1} S₂ = 0.3·25 + 0.7·20 = 7.5 + 14 = 21.5 S₃ = 0.3·30 + 0.7·21.5 = 9 + 15.05 = 24.05 S₄ = 0.3·28 + 0.7·24.05 = 8.4 + 16.835 = 25.235 S₅ = 0.3·35 + 0.7·25.235 = 10.5 + 17.6645 = 28.1645

🐍 Python で再現

1
2
3
4
5
6
7
import numpy as np
x = np.array([20, 25, 30, 28, 35])
alpha = 0.3
S = [x[0]]
for xt in x[1:]:
    S.append(alpha*xt + (1-alpha)*S[-1])
print(f"S: {np.round(S, 3)}")

📤 実行結果

S: [20. 21.5 24.05 25.235 28.164]

💬 手計算 (Step 2) S₅ ≈ 28.165 と Python 出力が完全一致。

🐍 Python 実装バリエーション — statsmodels / prophet / sktime / darts

① statsmodels(標準ライブラリ、 ETSフレームワーク)

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 L3221(消費支出(二人以上の世帯)) 北海道 296,888 東京都 341,320 沖縄県 251,222 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# ── この抜粋で使うデータを用意します(東京都の消費支出、12 年度分の年次系列)──
import pandas as pd
from statsmodels.tsa.holtwinters import ExponentialSmoothing

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
tokyo = df[df['Prefecture'] == '東京都'].sort_values('SSDSE-B-2026')
ts = tokyo.set_index(pd.PeriodIndex(tokyo['SSDSE-B-2026'], freq='Y'))['L3221'].astype(float)
print('系列長 =', len(ts), '(年次データなので季節周期はありません)')

# 単純指数平滑(SES)— 水準だけを追う
ses = ExponentialSmoothing(ts, trend=None, seasonal=None).fit(optimized=True)
print('alpha:', round(ses.params['smoothing_level'], 4))
print('3 年先予測:')
print(ses.forecast(3).round(0))

# 減衰トレンド付き Holt
# ※ seasonal='add', seasonal_periods=12 は「月次データ」用の設定。
#    SSDSE-B は年次 12 点しかないので、12 周期の季節を当てはめると
#    「都道府県の並び順」や「年の並び」を季節と誤認する。ここでは trend のみ使う。
holt = ExponentialSmoothing(ts, trend='add', seasonal=None, damped_trend=True).fit()
print('Holt(damped) の 3 年先予測:')
print(holt.forecast(3).round(0))
📤 実行例(実測) 系列長 = 12 (年次データなので季節周期はありません) alpha: 0.0 3 年先予測: 2024 327682.0 2025 327682.0 2026 327682.0 Freq: Y-DEC, dtype: float64 Holt(damped) の 3 年先予測: 2024 329484.0 2025 329700.0 2026 329916.0 Freq: Y-DEC, dtype: float64

② statsmodels の状態空間版(より高機能)

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 L3221(消費支出(二人以上の世帯)) 北海道 296,888 東京都 341,320 沖縄県 251,222 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# ── この抜粋で使うデータを用意します(東京都の消費支出、12 年度分の年次系列)──
import pandas as pd
from statsmodels.tsa.exponential_smoothing.ets import ETSModel

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
tokyo = df[df['Prefecture'] == '東京都'].sort_values('SSDSE-B-2026')
ts = tokyo.set_index(pd.PeriodIndex(tokyo['SSDSE-B-2026'], freq='Y'))['L3221'].astype(float)

# seasonal='add', seasonal_periods=12 は「月次データを 2 周期以上(24 点以上)」持つときの設定。
# SSDSE-B は年次 12 点しかないので、ここでは季節成分を外して状態空間版 ETS を当てる。
model = ETSModel(ts, error='add', trend='add', seasonal=None)
res = model.fit(disp=False)
print(res.summary())
pred = res.get_prediction(start=len(ts), end=len(ts) + 4)
print(pred.summary_frame())  # 予測区間付き
📤 実行例(実測) ETS Results ============================================================================== Dep. Variable: L3221 No. Observations: 12 Model: ETS(AAN) Log Likelihood -122.025 Date: Sun, 16 Aug 2026 AIC 254.049 Time: 17:44:44 BIC 256.474 Sample: 12-31-2012 HQIC 253.152 - 12-31-2023 Scale 39807214.873 Covariance Type: approx …(以下略)

③ Prophet(Meta製、 解釈性◎)

📥 入力例(SSDSE-B-2026 全体:564 行 × 112 列 = 47 都道府県 × 2012〜2023 年) 年度 地域コード 都道府県 A1101(総人口) A1303(65歳以上人口) A4101(出生数) … 2023 R01000 北海道 5,092,000 1,681,000 24,430 … 2023 R13000 東京都 14,086,000 3,205,000 86,348 … 2023 R47000 沖縄県 1,468,000 350,000 12,549 … …(残り 112 列は住宅・家計・教育・医療など)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
from prophet import Prophet
import pandas as pd

df = pd.read_csv('data/raw/SSDSE-A-2024.csv', encoding='shift_jis', skiprows=1)
prophet_df = df.rename(columns={'年月': 'ds', '消費支出_東京': 'y'})

m = Prophet(yearly_seasonality=True, weekly_seasonality=False)
m.fit(prophet_df)

future = m.make_future_dataframe(periods=12, freq='M')
forecast = m.predict(future)
print(forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']].tail())
m.plot(forecast)

④ sktime(scikit-learn風の時系列API)

1
2
3
4
5
6
7
8
9
from sktime.forecasting.exp_smoothing import ExponentialSmoothing as SktimeES
from sktime.forecasting.base import ForecastingHorizon
import numpy as np

forecaster = SktimeES(trend='add', seasonal='add', sp=12)
forecaster.fit(ts)
fh = ForecastingHorizon(np.arange(1, 13), is_relative=True)
y_pred = forecaster.predict(fh)
print(y_pred)

⑤ darts(深層学習も含む統一API)

1
2
3
4
5
6
7
8
from darts import TimeSeries
from darts.models import ExponentialSmoothing as DartsES

series = TimeSeries.from_dataframe(df, time_col='年月', value_cols='消費支出_東京')
model = DartsES()
model.fit(series)
pred = model.predict(n=12, num_samples=500)  # サンプリングで予測区間
print(pred.quantile_timeseries(0.05), pred.quantile_timeseries(0.95))

⚠️ 指数平滑法の落とし穴 — 拡張版(実務で本当に困る5+件)

  1. 季節性を見逃した単純平滑:明確な周期性(月次・週次)があるデータに単純指数平滑(SES)を適用すると、 ピークとボトムを取り損ね、 予測誤差が体系的に偏る。 周期性があれば必ず Holt-Winters(ETS(A,N,A)や(M,N,M))か SARIMA を使う。 自己相関プロット(ACF/PACF)で周期性を事前確認するのが鉄則。
  2. α の手動設定による過剰追従/過剰平滑:α を過剰に大きく(0.9以上)すると平滑値がほぼ生データになり、 ノイズに追従しすぎて予測性能が悪化する。 逆に α を小さく(0.05以下)すると変化に反応が遅れ、 構造変化を捉えられない。 statsmodels の ExponentialSmoothing で optimized=True を使い、 最尤推定で自動決定するのが基本。
  3. 欠損値・不規則間隔の扱い:指数平滑は 等間隔の時系列 を前提とする。 月次データで一部の月がない場合、 補完するか状態空間モデルでミッシングを扱う必要がある。 不規則間隔なら Kalman filter ベースの方法(pykalman、 statsmodels の UnobservedComponents)を検討。
  4. トレンドの線形仮定:Holt's 法は線形トレンドを仮定するため、 長期予測では 無限に発散 してしまう。 現実の経済データは飽和や反転を含むため、 「減衰トレンド(damped trend、 φ<1)」を入れることで長期予測を現実的に保つ。 過剰な楽観/悲観予測を防ぐ。
  5. 外挿(予測区間)の過信:点予測だけ報告して予測区間を示さないと、 予測の不確実性が伝わらない。 statsmodels の get_prediction で 95% 予測区間を計算し、 ファネルチャートで可視化する。 「予測値 ± 2σ」を提示する習慣を。
  6. 構造変化への対応の遅れ:コロナ禍のような 体制変化(regime change) が起きると、 過去データの重みが大きい指数平滑は反応が遅れる。 構造変化点を検出(CUSUM、 Bayesian online change point detection)してモデルを再学習する仕組みが必要。
  7. 加法 vs 乗法モデルの選択:季節振幅がレベルに比例して大きくなる場合(売上が大きい月ほど季節変動も大)は乗法モデル、 一定なら加法モデルを使う。 誤った選択は予測精度に致命的影響。 残差プロットで判断する。

⚠️ 指数平滑法を使う前に知っておくべき 7 つの落とし穴

  1. α の自動最適化が α→1 に張り付く — トレンドがあるのに SES を使うと尤度最大化で α=0.99 になり「直近値そのままコピー」予測になる。 残差プロットを必ず確認し、 ランダムでなければ Holt 以上へ進む。
  2. 初期値の選び方で 10-20% 性能が変わる — statsmodels の initialization_method='estimated' は MLE で初期水準・初期トレンドも推定するが、 短い時系列(n<15)では収束しないことがある。 'heuristic' や手動指定との比較が必須。
  3. 季節周期 m の誤指定で完全に予測を外す — 年次 SSDSE で誤って m=12 と指定すると、 「12 年前」を参照する季節成分が立ち上がってしまう。 必ずデータの取得間隔と m を一致させる。
  4. 外挿は短期向け、 長期は減衰必須 — Holt 線形を 20 期先まで外挿すると無限に発散する。 5 期以上先を予測したいなら必ず damped_trend=True に。 M4 コンペで 5 万シリーズ平均、 damped が 5-10% 優位。
  5. 構造変化(レジームシフト)に対応できない — コロナ前後・震災前後など平均水準が突如変わると、 指数平滑は数期かけてゆっくり追随する。 変化点検出ruptures)で時系列を分割するか、 介入変数を入れた状態空間モデルへ移行。
  6. 欠損値処理が組み込まれていない — Excel の指数平滑は欠損をスキップするが、 statsmodels の Holt は NaN を許さない。 線形補間(df.interpolate())や状態空間ベース推定(UnobservedComponents)に切替が必要。
  7. 予測区間は誤差の正規性を仮定 — ETS の予測区間は誤差項が正規分布に従うことを仮定。 残差にヘビーテールがあると予測区間がアンダーカバー。 ブートストラップ予測区間(forecast::forecast(model, bootstrap=TRUE))で代替。

🔁 ARIMA・状態空間・Prophet との関係 — 「等価性」と「使い分け」

指数平滑法は孤立した手法ではなく、 ARIMA・状態空間モデル・Prophet と数理的に**部分的等価**でつながっている。 これを知ると「どれを使うか」の判断が論理的になる。

📊 表: 指数平滑法と他手法の等価性

指数平滑モデル対応する ARIMA状態空間表現
SESARIMA(0,1,1)局所水準モデル
Holt 線形ARIMA(0,2,2)局所線形トレンドモデル
減衰 HoltARIMA(1,1,2)減衰トレンド状態空間
Holt-Winters 加法SARIMA(0,1,m+1)(0,1,0)_m基本構造時系列モデル

🐍 ETSModel 自動選択 — 30 通りから AICc 最小

このコードでやること: statsmodels.tsa.exponential_smoothing.ETSModel で error/trend/season の組み合わせを自動探索する R の ets() 相当を Python で再現。

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) 北海道 5,092,000 東京都 14,086,000 沖縄県 1,468,000 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# ── この抜粋で使うデータを用意します(東京都の総人口、直近 10 年度)──
import pandas as pd
from statsmodels.tsa.exponential_smoothing.ets import ETSModel

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
tokyo = df[df['Prefecture'] == '東京都'].sort_values('SSDSE-B-2026').tail(10)
y = tokyo['A1101'].values.astype(float)

configs = [(e, t, None, d)
           for e in ['add', 'mul']
           for t in [None, 'add']
           for d in [True, False] if not (t is None and d)]

results = []
for e, t, s, d in configs:
    try:
        m = ETSModel(y, error=e, trend=t, seasonal=s,
                     damped_trend=d if t else False).fit(disp=False)
        results.append((f"E={e} T={t} D={d}", m.aicc))
    except Exception:
        pass

for name, aicc in sorted(results, key=lambda x: x[1])[:5]:
    print(f"{name:30s} AICc = {aicc:.2f}")

📤 実行例:

E=add T=None D=False AICc = 266.49 E=mul T=None D=False AICc = 266.64 E=mul T=add D=False AICc = 278.80 E=add T=add D=False AICc = 278.84 E=add T=add D=True AICc = 288.00

💬 東京人口では **トレンドを持たない水準のみモデル(加法誤差, T=None)** が AICc 最小。 前節で SES/Holt の α→1・β→0 と縮退したのと同じ理由で、 n=10 と短い年次系列では「トレンドを明示的に持つ利点」を AICc が支持せず、 単純な水準モデルが選ばれる。 誤差項の add/mul 差はわずかで、 系列変動が小さいことを反映している。

🐍 Prophet との比較(年次データ)

このコードでやること: 同じ東京人口 10 年に Prophet を当て、 damped Holt と予測精度を比較する。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# pip install prophet
from prophet import Prophet

prop_df = pd.DataFrame({'ds': pd.to_datetime(tokyo['年度'].astype(str)),
                        'y': tokyo['A1101'].values})
mp = Prophet(yearly_seasonality=False).fit(prop_df)
future = mp.make_future_dataframe(periods=1, freq='YS')
pred = mp.predict(future)
print(f"Prophet ŷ(2024) = {pred['yhat'].iloc[-1]:.1f}")
print(f"damped Holt ŷ(2024) = {damped.forecast(1)[0]:.1f}")

📤 実行例:

Prophet ŷ(2024) = 14118.7 damped Holt ŷ(2024) = 14112.9

💬 差は数千人程度とわずか。 短い年次データでは Prophet の柔軟性は活きず、 計算コストの低い damped Holt がほぼ同等。 Prophet が有利になるのは「日次・週次で休日効果あり」のケース。

🗺️ 指数平滑法の手法選択フローチャート

Q1: 時系列にトレンド (傾向) はあるか?

Q2: 季節性 (周期パターン) はあるか?

Q3: 系列長 (サンプル数) は?

Q4: 何を最適化したいか?

📏 効果量の参照表

p値だけでなく効果量も併記するのが現代統計の標準。 主要な指標と Cohen の解釈基準:

統計量 効果量
2群平均差Cohen's d0.20.50.8
相関r0.10.30.5
線形回帰0.020.130.26
ANOVAη² (eta²)0.010.060.14
χ²Cramér's V0.10.30.5
ロジスティックOdds Ratio1.52.54.0

🚀 実務応用の深掘り

典型的なプロジェクトの流れ

  1. 問題理解:ステークホルダーとの対話、 KGI/KPI 設定
  2. データ収集:内部DB、 公的データ(SSDSE等)、 API
  3. EDA:データの全体像把握、 異常検出
  4. 仮説立案:ドメイン知識からの仮説
  5. モデリング:シンプルから複雑へ段階的に
  6. 検証:CV、 ホールドアウト、 A/Bテスト
  7. 解釈:可視化、 SHAP、 部分依存プロット
  8. 展開:本番デプロイ、 監視

ベストプラクティス

論文・コンペでよく使う言い回し

日本語 英語
統計的に有意statistically significant
効果量effect size
95%信頼区間95% confidence interval (CI)
標本サイズsample size
検出力statistical power
第1種の誤りType I error / false positive
第2種の誤りType II error / false negative
多重比較問題multiple comparisons problem
過学習overfitting
汎化性能generalization
交差検証cross-validation (CV)

統計データ活用コンペでのコツ

🗺️ 概念マップ — 3つの視点で体系を理解する

指数平滑法 がデータサイエンスの体系の中でどこに位置するかを、 3つの異なる視点で可視化します。 同じ情報でも見方を変えると気付きが変わります。

📍 体系階層のパス

🌐 統計・データサイエンス › 時系列 › 予測 › 指数平滑法(直近の値ほど重く見る平滑化)

① 🔗 関係マップ — 「他の手法とどう繋がっているか」

中心に 指数平滑法 を置き、 そこから 時系列分析・ARIMA・VAR 計 3 個の用語へ、 前提・兄弟・発展形といった関係を矢印で結んでいます。 線がどちら向きかを見れば、 先に読むべき用語あとから読む用語が分かります。 ノードはドラッグで動かせ、 ホイールでズーム、 クリックでその用語のページへ遷移します。

凡例:現在の用語上位カテゴリ兄弟(並列)前提発展形応用先2階層先

② ⭕ 包含マップ — 「どのカテゴリに含まれているか」

大きな円が小さな円を包含する Circle Packing 図。 「指数平滑法」は緑色でハイライト

📍現在地:統計・データサイエンス

③ 🌳 ツリーマップ — 「面積で見るボリューム比較」

長方形を入れ子に分割した Treemap 図。 各分野の規模感を面積で比較。 「指数平滑法」は緑色でハイライト

🎯 3つのマップの使い分け

マップ 分かること こんな時に見る
🔗 関係マップ手法間の横の関係(前提→発展→応用)「次に何を学べばよい?」 学習順序の判断
⭕ 包含マップ分類体系の入れ子構造(上位⊃下位)「この手法はどんなジャンルに属する?」
🌳 ツリーマップ分野の規模比較(面積=ボリューム)「データサイエンス全体の俯瞰像」

💡 3 つの図は同じ位置関係を別の角度から描いています。 関係マップは 指数平滑法隣に何が並ぶかを、 包含マップとツリーマップは 統計・データサイエンス予測 → 指数平滑法 という入れ子の位置を示します。 「予測には他に何があったか」を思い出したいときは包含マップを、 「次に何を読むか」を決めたいときは関係マップを開いてください。

🔗 隣接手法への橋渡し

「指数平滑法」は単独で完結せず、 隣接する手法と接続することで分析パイプラインの一部として機能する。 以下に具体的な接続関係を示す。

指数平滑法は (1) 時系列プロット + ACF/PACF で構造把握 → (2) trend/seasonality 成分の有無で SES / Holt / Holt-Winters / ETS を選択 → (3) AICc 最小化で α/β/γ パラメータ推定 → (4) ローリングウィンドウ CV で out-of-sample 評価、 という ETS フレームワーク (Hyndman et al. 2008) に整理される。 月次データなら m=12、 週次なら m=7 の季節周期を明示する。

🌳 手法選択フロー

「exponential smoothing」を含む手法選択は、 データの性質・分析目的・運用制約の 3 軸で決まる。 以下に典型シナリオと対応する手法の組合せを示す。

典型シナリオ別の手法選択

シナリオ重視する観点候補手法
トレンド・季節性なし (定常)過去値の指数加重平均単純指数平滑 SES (Brown 1959)
トレンドあり・季節性なしレベル + トレンド成分分離Holt 法 (Holt 1957) / 減衰トレンド
トレンド + 季節性あり加法 or 乗法分解Holt-Winters (Winters 1960)
複数季節性 / 祝日効果事前情報 + Bayesian 推定Prophet (Taylor & Letham 2018) / TBATS
自己相関構造が複雑AR / MA / 差分ARIMA (Box & Jenkins 1970)
不確実性を明示したい予測区間 / ベイズETS 状態空間 (Hyndman et al. 2008)

選んだ後の検証ステップ

  1. 前処理確認: 標準化 / 欠損処理 / カテゴリ変数のエンコード が適切か
  2. ハイパラ調整: 交差検証で安定する値を選ぶ
  3. 性能評価: タスクに応じた指標 (RMSE / Accuracy / F1 / AUC / シルエット等) を複数併用
  4. 頑健性チェック: 別手法 / 別シードで結果が大きく違わないか確認
  5. 解釈: 結果を分野知識と照らし合わせ、 意味のある発見になっているか検討

🎮 触って理解する

ノイズを含む時系列に対して、 単純指数平滑 $S_t = \alpha\,y_t + (1-\alpha)\,S_{t-1}$ を「その場で」計算します。 下のスライダーで平滑化係数 α を動かすと、 赤い平滑化系列と、 過去の観測に掛かる重みの指数減衰がリアルタイムに変化します。 灰色の点はドラッグで編集できます(スマホはタップしてなぞる)。 α を大きくすると直近を重視して反応的に、 小さくすると滑らかだが遅れて追従する—— この 追従性とノイズ除去のトレードオフ を体感してください。

直近の重み (α):0.30 1期前の残存 (1−α):0.70 データの平均遅れ (1−α)/α:2.33 1期先予測 RMSE:
— — 灰色(点線・点):ノイズを含む観測 $y_t$(ドラッグで編集可) — 赤:平滑化系列 $S_t$

縦軸=値(0〜120)/横軸=時刻 t。 灰色の点を上下にドラッグすると観測値が変わり、 赤い平滑化系列が即座に再計算されます。

過去の観測に掛かる実効重み:$w_k = \alpha(1-\alpha)^k$(k=0 が最新)。 α が大きいほど直近に集中し、 小さいほど遠い過去まで薄く広がります。

縦軸=重み(0〜1)。 全ての k にわたる重みの総和は 1 になります($\sum_{k=0}^{\infty}\alpha(1-\alpha)^k=1$)。

💡 直感:指数的に減衰する加重平均

漸化式を展開すると $S_t = \alpha\sum_{k=0}^{t-1}(1-\alpha)^k\,y_{t-k} + (1-\alpha)^t S_0$ となり、 過去の観測すべての加重平均で、 その重みが $(1-\alpha)^k$ で指数減衰することが分かります。 上の棒グラフはまさにこの $w_k=\alpha(1-\alpha)^k$。 α=0.3 なら 5 期前の重みは元の $0.7^5\approx17\%$、 10 期前は約 3%。 「データの平均遅れ」は $(1-\alpha)/\alpha$ 期で、 α=0.3 なら約 2.3 期分だけ過去に重心が寄った平均を見ていることになります。

🚧 よくある落とし穴

🚀 発展:Holt 法・Holt-Winters 法

トレンドの取り損ねは、 水準 $\ell_t$ に加えて傾き $b_t$ を第2の指数平滑(係数 β)で追跡する Holt 線形トレンド法で解決します:$\ell_t=\alpha y_t+(1-\alpha)(\ell_{t-1}+b_{t-1})$、 $b_t=\beta(\ell_t-\ell_{t-1})+(1-\beta)b_{t-1}$。 さらに季節成分 $s_t$(係数 γ)を第3の平滑で足したのが Holt-Winters 法(加法/乗法)で、 トレンド+季節を同時に扱えます。 長期予測が線形に発散するのを抑える減衰トレンド(φ)や、 これらを統一的に扱う状態空間 ETS も同じ「指数加重」の発想の延長線上にあります。

関連ページ:時系列データ自己相関定常性ARIMAノイズ。 (Holt 法・Holt-Winters 法・ETS は本ページ上部「Python実装パターン」「手法選択フロー」で詳説しています。)

🔍 解説を深める — α を「窓幅」と「遅れ」に翻訳する

本ページの上部では「α は直近をどれだけ重視するかのダイヤル」と学んだ。 このセクションでは一歩進めて、 α を 移動平均の窓幅・重心の遅れ・半減期 という 3 つの実務的な物差しに翻訳し、 さらに「トレンドがあるとき SES がどれだけ系統的に遅れるか」を 公式と SSDSE-B-2026 の実測値の突き合わせ で確認する。 上の対話ウィジェットで体感した「遅れ」を、 ここでは数式と実データで定量化する。

💡 直感 — α の 3 つの言い換え

「α=0.3 は結局、 何期分の平均なのか?」という問いには、 次の 3 つの換算式で答えられる。

α等価 SMA 窓幅 (2/α−1)重心の遅れ (1−α)/α半減期
0.119.0 期9.00 期6.58 期
0.29.0 期4.00 期3.11 期
0.35.7 期2.33 期1.94 期
0.53.0 期1.00 期1.00 期
0.81.5 期0.25 期0.43 期

つまり「α=0.3 の SES」は「窓幅約 6 期の移動平均に近い滑らかさで、 常に約 2.3 期ぶん過去に重心を置いた平均」と読める。 年次の SSDSE データ(1 期=1 年)なら、 α=0.3 は「2 年ちょっと前の姿を見ている」ことになる。 この換算感覚があると、 自動推定された α を見た瞬間に「このモデルはどれくらい過去を引きずるか」を報告書の言葉に翻訳できる。

⚠️ 落とし穴(重要) — トレンド下の SES は「一定量」遅れ続ける

上部の落とし穴では「トレンドがあると SES は遅れる」と定性的に述べた。 実は遅れの大きさは公式で予測できる。 系列が毎期 $b$ ずつ増える線形トレンドを持つとき、 SES の平滑値は定常状態で $$y_t - S_t \;\to\; b\cdot\frac{1-\alpha}{\alpha}$$ だけ 一定量、 恒常的に 実測を下回る(重心の遅れ (1−α)/α 期 × 毎期の増分 b)。 これを東京都の総人口 A1101(SSDSE-B-2026、 2012-2023 年、 単位: 人)で実測検証する。 2012→2019 年の平均増分は $b \approx$ +110,429 人/年。 α=0.3 なら理論遅れは $110{,}429 \times 0.7/0.3 \approx$ 257,667 人 と予測される。 実際に α=0.3 固定・$S_0=y_{2012}$ で漸化式を回すと:

# 東京都 A1101(人)、α=0.3 固定 SES の実測遅れ 2019年: 実測 y = 14,007,000 平滑 S = 13,755,079 遅れ = 251,921 人 ← 理論値 257,667 とほぼ一致 2023年: 実測 y = 14,086,000 平滑 S = 13,981,342 遅れ = 104,658 人 ← トレンド鈍化で遅れが縮小

💬 増加が安定していた 2019 年時点の遅れ 251,921 人 は理論値 257,667 人とほぼ一致し、 「SES はトレンド × 重心遅れのぶん必ず下振れする」ことが実データで確認できる。 一方 2020 年以降はコロナ禍で増加が鈍化したため(2021 年は −37,594 人と減少)、 2023 年の遅れは 104,658 人まで縮んだ。 遅れはトレンドに比例するので、 トレンドが消えれば SES は追いつく——逆に言えば、 トレンドが続く限り α をどれだけ調整しても SES の遅れはゼロにならない(α→1 にすると遅れは消えるが今度はただの naïve 予測になる)。 これが「トレンドには Holt 法」の定量的な根拠である。

もう 1 つ、 pandas 利用時の見落としやすい罠が ewm()adjust 引数。 教科書の SES 漸化式 $S_t = \alpha y_t + (1-\alpha)S_{t-1}$ に一致するのは adjust=False の方で、 既定値の adjust=True は「有限個の重みを総和 1 に正規化した加重平均」を返すため、 系列の序盤で値がずれる。 同じ東京都系列(α=0.3)で比較すると、 2 年目(2013 年)の平滑値は adjust=False で 13,255,900 人、 adjust=True で 13,276,941 人と 約 21,041 人 食い違う(系列が長くなるほど差は縮み、 2023 年時点では約 10,489 人差)。 statsmodels の SES と pandas の ewm を突き合わせて「値が合わない」と混乱する典型原因なので、 検算には必ず adjust=False を指定する。

🚀 発展 — 1 行 EWMA から分野横断の「兄弟」へ

SES の計算エンジンは statsmodels だけではない。 平滑値そのものが欲しいだけなら s.ewm(alpha=0.3, adjust=False).mean() の 1 行で漸化式と同じ結果が得られ、 span=(等価窓幅)や halflife=(半減期)でも指定できる——上の換算表はそのまま引数の読み替え表になる。 47 都道府県 × 100 超列を一括平滑するなら groupby('Prefecture').transform(lambda s: s.ewm(alpha=0.3, adjust=False).mean()) のように groupby と組み合わせるのが高速で、 モデル推定(α の最尤推定・予測区間)が必要になった段階で statsmodels に切り替えるのが実務的な住み分けである。

さらに視野を広げると、 「指数加重」という同じ数学が分野ごとに別の名前で使われている。 品質管理では EWMA 管理図(小さな工程シフトの検出に強い)、 金融では RiskMetrics 型の EWMA ボラティリティ推定(日次で λ=0.94、 すなわち α=0.06 が慣用値)、 深層学習では Adam や RMSProp の勾配・2 乗勾配の指数移動平均、 強化学習では TD 学習の学習率がまさに α の役割を果たす。 「直近を重く、 過去を指数的に忘れる」という 1 つの原理を軸に、 予測(本ページ)・監視(管理図)・推定(ボラティリティ)・最適化(Adam)を横断して眺めると、 指数平滑法は時系列予測の一手法ではなく 逐次更新アルゴリズムの共通言語 だと分かる。 理論面では、 SES が ARIMA(0,1,1) と等価(上部の等価性の表)であることから、 この「忘却しながらの平均」はランダムウォーク+観測ノイズという局所水準モデルの最適フィルタ(カルマンフィルタの定常解)でもある。