STEP 34:時系列分析の実務応用

📊 STEP 34: 時系列分析の実務応用

高度な予測手法でより正確な売上予測を実現しよう

📋 このステップで学ぶこと

  • 指数平滑法による予測
  • ARIMAモデルの基礎
  • Prophetライブラリの活用
  • 実務での月次売上予測
  • 複数モデルの比較と選択

学習時間の目安: 4時間

🔍 1. 指数平滑法(Exponential Smoothing)

基本概念

📌 最近のデータに指数的に大きな重みをつける

移動平均法の進化版で、より柔軟な予測が可能

移動平均法の問題:
・すべての期間に同じ重み
・古いデータも新しいデータも同等
・急激な変化に対応しにくい

指数平滑法の特徴:
・最新データに最大の重み
・過去に遡るほど重みが減少
・トレンドや季節性も考慮可能

3つのレベル:

1. 単純指数平滑法(SES)
・トレンドも季節性もない場合
・横ばいデータに適用

2. ダブル指数平滑法(Holt法)
・トレンドあり、季節性なし
・上昇/下降トレンドに対応

3. トリプル指数平滑法(Holt-Winters法)
・トレンドも季節性もあり
・実務で最も使われる
・売上予測に最適

指数平滑法の数式

💡 単純指数平滑法(SES)の計算式
予測式:
F_{t+1} = α × Y_t + (1-α) × F_t

各記号の意味:
・F_{t+1}: 次期の予測値
・Y_t: 今期の実績値
・F_t: 今期の予測値
・α: 平滑化係数(0〜1)

αの選び方:
・α = 0.1〜0.3: 安定したデータ(変動小)
・α = 0.4〜0.6: 一般的なデータ
・α = 0.7〜0.9: 変動が大きいデータ

具体例(α = 0.3):
今期実績: 100万円
今期予測: 90万円

次期予測 = 0.3 × 100 + 0.7 × 90
= 30 + 63
= 93万円

→ 最新の実績を30%、過去の予測を70%反映

指数平滑法の実装

# ============================================ # 指数平滑法による売上予測 # ============================================ # 指数平滑法とは? # → 最新データに大きな重み、過去ほど小さな重み # → 移動平均法の進化版 # → トレンドや季節性も考慮可能 import pandas as pd import numpy as np import matplotlib.pyplot as plt from statsmodels.tsa.holtwinters import ExponentialSmoothing import warnings warnings.filterwarnings(‘ignore’) # ============================================ # サンプルデータ作成(月次売上 – 3年分) # ============================================ np.random.seed(42) # pd.date_range(): 日付の連続データを生成 # ‘2021-01-01’: 開始日 # ‘2024-12-01′: 終了日 # freq=’MS’: 月初(Month Start) months = pd.date_range(‘2021-01-01’, ‘2024-12-01′, freq=’MS’) # 時系列の3要素を作成 # np.linspace(): 等間隔の数値を生成 # 100から160まで、len(months)個の数値 trend = np.linspace(100, 160, len(months)) # 上昇トレンド # np.sin(): サイン波で季節パターンを作成 # 2 * np.pi / 12: 12ヶ月で1周期 # 25 *: 振幅±25の変動 seasonality = 25 * np.sin(np.arange(len(months)) * 2 * np.pi / 12) # np.random.normal(): 正規分布に従う乱数 # 平均0、標準偏差5のノイズ noise = np.random.normal(0, 5, len(months)) # 3要素を合成 sales = trend + seasonality + noise # データフレーム作成 df = pd.DataFrame({ ‘date’: months, ‘sales’: sales }) # ============================================ # データを訓練とテストに分割 # ============================================ # 85%を訓練用、15%をテスト用 train_size = int(len(df) * 0.85) train = df[:train_size] test = df[train_size:] print(“【データ分割】”) print(f”訓練データ: {len(train)}ヶ月”) print(f”テストデータ: {len(test)}ヶ月”) print() # ============================================ # 精度評価関数 # ============================================ def calculate_metrics(actual, predicted): “”” 予測精度を計算 Parameters: ———– actual : array – 実績値 predicted : array – 予測値 Returns: ——– tuple – (MAE, RMSE, MAPE) “”” mae = np.mean(np.abs(actual – predicted)) rmse = np.sqrt(np.mean((actual – predicted)**2)) mape = np.mean(np.abs((actual – predicted) / actual)) * 100 return mae, rmse, mape # ============================================ # 1. 単純指数平滑法(SES) # ============================================ # ExponentialSmoothing()のパラメータ: # trend=None: トレンド成分なし # seasonal=None: 季節性成分なし model_ses = ExponentialSmoothing( train[‘sales’], trend=None, seasonal=None ).fit() # .forecast(): 未来を予測 # steps: 予測する期間数 forecast_ses = model_ses.forecast(steps=len(test)) # ============================================ # 2. ダブル指数平滑法(Holt法) # ============================================ # trend=’add’: 加法トレンド(線形成長) # → トレンドを考慮するが季節性は考慮しない model_holt = ExponentialSmoothing( train[‘sales’], trend=’add’, seasonal=None ).fit() forecast_holt = model_holt.forecast(steps=len(test)) # ============================================ # 3. トリプル指数平滑法(Holt-Winters法) # ============================================ # trend=’add’: 加法トレンド # seasonal=’add’: 加法季節性 # seasonal_periods=12: 12ヶ月周期(年次季節性) model_hw = ExponentialSmoothing( train[‘sales’], trend=’add’, seasonal=’add’, seasonal_periods=12 ).fit() forecast_hw = model_hw.forecast(steps=len(test)) # ============================================ # 精度比較 # ============================================ print(“【予測精度比較】”) print() mae_ses, rmse_ses, mape_ses = calculate_metrics( test[‘sales’].values, forecast_ses ) print(“単純指数平滑法(SES):”) print(f” MAE: {mae_ses:.2f}”) print(f” RMSE: {rmse_ses:.2f}”) print(f” MAPE: {mape_ses:.2f}%”) print() mae_holt, rmse_holt, mape_holt = calculate_metrics( test[‘sales’].values, forecast_holt ) print(“ダブル指数平滑法(Holt):”) print(f” MAE: {mae_holt:.2f}”) print(f” RMSE: {rmse_holt:.2f}”) print(f” MAPE: {mape_holt:.2f}%”) print() mae_hw, rmse_hw, mape_hw = calculate_metrics( test[‘sales’].values, forecast_hw ) print(“トリプル指数平滑法(Holt-Winters):”) print(f” MAE: {mae_hw:.2f}”) print(f” RMSE: {rmse_hw:.2f}”) print(f” MAPE: {mape_hw:.2f}%”) print() # ============================================ # 最適モデルの選択 # ============================================ # min(): 最小値を持つキーを取得 # key=models.get: 値(MAPE)で比較 models = { ‘SES’: mape_ses, ‘Holt’: mape_holt, ‘Holt-Winters’: mape_hw } best_model = min(models, key=models.get) print(f”【最適モデル】{best_model} (MAPE: {models[best_model]:.2f}%)”) print() # ============================================ # 未来の予測(次の6ヶ月) # ============================================ future_forecast = model_hw.forecast(steps=6) # pd.DateOffset(): 日付をずらす # months=1: 1ヶ月後 future_dates = pd.date_range( df[‘date’].iloc[-1] + pd.DateOffset(months=1), periods=6, freq=’MS’ ) print(“【未来予測(次の6ヶ月)】”) for date, sales in zip(future_dates, future_forecast): print(f”{date.strftime(‘%Y年%m月’)}: {sales:.1f}百万円”)

可視化コード

# ============================================ # 可視化 # ============================================ # plt.subplots(): 複数のグラフを配置 # 2, 2: 2行2列(計4グラフ) # figsize: 図全体のサイズ fig, axes = plt.subplots(2, 2, figsize=(16, 10)) # ============================================ # グラフ1: 単純指数平滑法 # ============================================ ax1 = axes[0, 0] ax1.plot(train[‘date’], train[‘sales’], label=’訓練データ’, color=’blue’) ax1.plot(test[‘date’], test[‘sales’], label=’実績’, color=’green’, marker=’o’) ax1.plot(test[‘date’], forecast_ses, label=’予測’, color=’red’, linestyle=’–‘, marker=’s’) ax1.set_title(f’単純指数平滑法(SES)\nMAPE: {mape_ses:.1f}%’, fontsize=13, fontweight=’bold’) ax1.set_ylabel(‘売上(百万円)’, fontsize=11) ax1.legend() ax1.grid(alpha=0.3) # ============================================ # グラフ2: ダブル指数平滑法 # ============================================ ax2 = axes[0, 1] ax2.plot(train[‘date’], train[‘sales’], label=’訓練データ’, color=’blue’) ax2.plot(test[‘date’], test[‘sales’], label=’実績’, color=’green’, marker=’o’) ax2.plot(test[‘date’], forecast_holt, label=’予測’, color=’red’, linestyle=’–‘, marker=’s’) ax2.set_title(f’ダブル指数平滑法(Holt)\nMAPE: {mape_holt:.1f}%’, fontsize=13, fontweight=’bold’) ax2.set_ylabel(‘売上(百万円)’, fontsize=11) ax2.legend() ax2.grid(alpha=0.3) # ============================================ # グラフ3: トリプル指数平滑法 # ============================================ ax3 = axes[1, 0] ax3.plot(train[‘date’], train[‘sales’], label=’訓練データ’, color=’blue’) ax3.plot(test[‘date’], test[‘sales’], label=’実績’, color=’green’, marker=’o’) ax3.plot(test[‘date’], forecast_hw, label=’予測’, color=’red’, linestyle=’–‘, marker=’s’) ax3.set_title(f’トリプル指数平滑法(Holt-Winters)\nMAPE: {mape_hw:.1f}%’, fontsize=13, fontweight=’bold’) ax3.set_xlabel(‘日付’, fontsize=11) ax3.set_ylabel(‘売上(百万円)’, fontsize=11) ax3.legend() ax3.grid(alpha=0.3) # ============================================ # グラフ4: 精度比較(棒グラフ) # ============================================ ax4 = axes[1, 1] methods = [‘SES’, ‘Holt’, ‘Holt-Winters’] mapes = [mape_ses, mape_holt, mape_hw] colors = [‘#ff9999’, ‘#66b3ff’, ‘#99ff99′] bars = ax4.bar(methods, mapes, color=colors, alpha=0.7, edgecolor=’black’) ax4.set_ylabel(‘MAPE (%)’, fontsize=11) ax4.set_title(‘予測精度比較(MAPE)’, fontsize=13, fontweight=’bold’) ax4.grid(axis=’y’, alpha=0.3) # 値を棒グラフ上に表示 for bar, mape in zip(bars, mapes): height = bar.get_height() ax4.text(bar.get_x() + bar.get_width()/2., height, f'{mape:.1f}%’, ha=’center’, va=’bottom’, fontsize=11) plt.tight_layout() plt.show()

📈 2. ARIMAモデルの基礎

ARIMAとは

💡 ARIMA = 自己回帰和分移動平均モデル
ARIMAの3つのパラメータ:

AR(p): 自己回帰(AutoRegressive)
・過去p期のデータを使用
・例: 今月の売上 = 先月の売上 × 係数 + …
・p=1: 先月だけ使用
・p=2: 先月と先々月を使用

I(d): 差分(Integrated)
・データを定常化するための差分回数
・トレンドを除去
・d=0: 差分なし(定常データ)
・d=1: 1階差分(今月 – 先月)

MA(q): 移動平均(Moving Average)
・過去q期の予測誤差を使用
・ランダムショックの影響を考慮
・q=1: 前期の誤差だけ使用

よく使われる設定:
・ARIMA(1,1,1): 基本形
・ARIMA(0,1,1): シンプル
・ARIMA(2,1,2): 複雑なパターン

ARIMAのパラメータ選択

📌 AIC(赤池情報量基準)でモデルを選択
AICとは:
・モデルの良さを評価する指標
・予測精度とモデルの複雑さのバランス
AICが小さいほど良いモデル

パラメータ選択の手順:
1. 複数のARIMAモデルを試す
2. 各モデルのAICを計算
3. AICが最小のモデルを採用

自動選択(auto_arima):
・pmdarima ライブラリを使用
・最適なp, d, qを自動で探索
・実務では自動選択が便利

ARIMAモデルの実装

# ============================================ # ARIMAモデルによる予測 # ============================================ # ARIMA = AutoRegressive Integrated Moving Average # AR(p): 過去の値を使った自己回帰 # I(d): 差分(トレンド除去) # MA(q): 過去の誤差を使った移動平均 from statsmodels.tsa.arima.model import ARIMA from statsmodels.graphics.tsaplots import plot_acf, plot_pacf # データ準備(同じデータを使用) train_arima = train[‘sales’].values test_arima = test[‘sales’].values # ============================================ # 複数のARIMAモデルを試す # ============================================ # 様々な(p, d, q)の組み合わせでAICを比較 arima_configs = [ (1, 1, 1), # 基本形 (0, 1, 1), # シンプル (2, 1, 2), # 複雑 (1, 1, 0), # MA項なし (0, 1, 2) # AR項なし ] print(“【ARIMAモデル比較】”) print() best_aic = float(‘inf’) # 無限大で初期化 best_config = None for config in arima_configs: try: # ARIMA()のパラメータ: # order=(p, d, q): ARIMAの次数 model = ARIMA(train_arima, order=config) model_fit = model.fit() # .aic: 赤池情報量基準 # → 小さいほど良いモデル aic = model_fit.aic print(f”ARIMA{config}: AIC = {aic:.2f}”) # より良いモデルが見つかったら更新 if aic < best_aic: best_aic = aic best_config = config except: print(f"ARIMA{config}: エラー(スキップ)") print() print(f"【最適モデル】ARIMA{best_config} (AIC: {best_aic:.2f})") print() # ============================================ # 最適モデルで予測 # ============================================ model_arima = ARIMA(train_arima, order=best_config) model_arima_fit = model_arima.fit() # .forecast(): 未来を予測 forecast_arima = model_arima_fit.forecast(steps=len(test_arima)) # 精度評価 mae_arima, rmse_arima, mape_arima = calculate_metrics( test_arima, forecast_arima ) print("【ARIMA予測精度】") print(f"MAE: {mae_arima:.2f}") print(f"RMSE: {rmse_arima:.2f}") print(f"MAPE: {mape_arima:.2f}%") print() # ============================================ # 可視化 # ============================================ plt.figure(figsize=(14, 6)) plt.plot(train['date'], train_arima, label='訓練データ', color='blue') plt.plot(test['date'], test_arima, label='実績', color='green', marker='o') plt.plot(test['date'], forecast_arima, label='ARIMA予測', color='red', linestyle='--', marker='s') plt.xlabel('日付', fontsize=12) plt.ylabel('売上(百万円)', fontsize=12) plt.title(f'ARIMAモデルによる予測\nARIMA{best_config}, MAPE: {mape_arima:.1f}%', fontsize=14, fontweight='bold') plt.legend(fontsize=11) plt.grid(alpha=0.3) plt.tight_layout() plt.show()

🚀 3. Prophetライブラリの活用

Prophetの特徴

📌 Facebook開発の実用的な時系列予測ライブラリ
Prophetの長所:
・設定がシンプル
・欠損値に強い
・外れ値に頑健
・休日の影響を考慮可能
・トレンド転換を自動検出
・不確実性の範囲(信頼区間)も出力

適している場合:
・季節性が強いデータ
・休日の影響が大きい
・長期予測が必要
・複数年のデータがある

基本的な使い方:
1. データを ds(日付)と y(値)に整形
2. Prophetオブジェクトを作成
3. fit()で学習
4. make_future_dataframe()で未来の日付
5. predict()で予測

Prophetの実装

# ============================================ # Prophetライブラリによる予測 # ============================================ # Prophet = Facebookが開発した時系列予測ライブラリ # → シンプルで使いやすい # → 休日の影響も考慮可能 # → 信頼区間も自動で計算 # インストール(初回のみ) # !pip install prophet –break-system-packages from prophet import Prophet # ============================================ # データ準備(Prophetの形式に変換) # ============================================ # Prophetは特定の列名を要求: # ds: 日付列 # y: 予測対象の値 df_prophet = df[[‘date’, ‘sales’]].copy() df_prophet.columns = [‘ds’, ‘y’] # 訓練とテストに分割 train_prophet = df_prophet[:train_size] test_prophet = df_prophet[train_size:] # ============================================ # Prophetモデルの作成 # ============================================ # Prophet()のパラメータ: # yearly_seasonality: 年次季節性(True/False) # weekly_seasonality: 週次季節性(月次データはFalse) # daily_seasonality: 日次季節性(月次データはFalse) # seasonality_mode: ‘additive'(加法) or ‘multiplicative'(乗法) # interval_width: 信頼区間の幅(0.95 = 95%) model_prophet = Prophet( yearly_seasonality=True, weekly_seasonality=False, daily_seasonality=False, seasonality_mode=’additive’, interval_width=0.95 ) # .fit(): モデルを学習 model_prophet.fit(train_prophet) # ============================================ # 未来のデータフレーム作成 # ============================================ # make_future_dataframe(): 予測用の日付を生成 # periods: 予測する期間数 # freq: 頻度(‘MS’ = 月初) future = model_prophet.make_future_dataframe( periods=len(test_prophet), freq=’MS’ ) # .predict(): 予測を実行 # → 予測値(yhat)、下限(yhat_lower)、上限(yhat_upper)を返す forecast_prophet = model_prophet.predict(future) # テストデータに対する予測値を抽出 # iloc[-len(test_prophet):]: 最後のlen(test_prophet)行 test_forecast = forecast_prophet.iloc[-len(test_prophet):][‘yhat’].values # 精度評価 mae_prophet, rmse_prophet, mape_prophet = calculate_metrics( test_prophet[‘y’].values, test_forecast ) print(“【Prophet予測精度】”) print(f”MAE: {mae_prophet:.2f}”) print(f”RMSE: {rmse_prophet:.2f}”) print(f”MAPE: {mape_prophet:.2f}%”) print() # ============================================ # 未来予測(次の12ヶ月) # ============================================ future_12 = model_prophet.make_future_dataframe(periods=12, freq=’MS’) forecast_12 = model_prophet.predict(future_12) print(“【未来予測(次の12ヶ月)】”) print() # 最後の12行(未来の予測)を表示 for i in range(-12, 0): row = forecast_12.iloc[i] date = row[‘ds’] yhat = row[‘yhat’] # 予測値 lower = row[‘yhat_lower’] # 下限(95%信頼区間) upper = row[‘yhat_upper’] # 上限(95%信頼区間) print(f”{date.strftime(‘%Y年%m月’)}: {yhat:.1f}百万円 ” f”[{lower:.1f}〜{upper:.1f}]”)

Prophetの可視化

# ============================================ # Prophetの可視化 # ============================================ fig, axes = plt.subplots(2, 1, figsize=(14, 10)) # ============================================ # グラフ1: 予測結果 # ============================================ # model_prophet.plot(): Prophet標準の予測グラフ # → 実績(黒点)、予測(青線)、信頼区間(水色帯) ax1 = axes[0] model_prophet.plot(forecast_prophet, ax=ax1) ax1.set_xlabel(‘日付’, fontsize=12) ax1.set_ylabel(‘売上(百万円)’, fontsize=12) ax1.set_title(f’Prophetによる予測(MAPE: {mape_prophet:.1f}%)’, fontsize=14, fontweight=’bold’) ax1.grid(alpha=0.3) # ============================================ # グラフ2: 成分分解 # ============================================ # plot_components(): トレンドと季節性を分解表示 # → トレンド: 長期的な傾向 # → 季節性: 周期的なパターン ax2 = axes[1] model_prophet.plot_components(forecast_prophet) plt.tight_layout() plt.show()

🏆 4. モデルの総合比較

全モデルの精度比較

# ============================================ # 全モデルの精度比較 # ============================================ import pandas as pd # 比較表を作成 comparison = pd.DataFrame({ ‘モデル’: [‘移動平均(6ヶ月)’, ‘SES’, ‘Holt’, ‘Holt-Winters’, ‘ARIMA’, ‘Prophet’], ‘MAPE’: [10.5, mape_ses, mape_holt, mape_hw, mape_arima, mape_prophet], ‘MAE’: [8.2, mae_ses, mae_holt, mae_hw, mae_arima, mae_prophet], ‘RMSE’: [10.1, rmse_ses, rmse_holt, rmse_hw, rmse_arima, rmse_prophet] }) # MAPEでソート(精度が高い順) comparison = comparison.sort_values(‘MAPE’) comparison = comparison.reset_index(drop=True) print(“【モデル精度ランキング】”) print(comparison.to_string(index=False)) print() # 最適モデル best_model_name = comparison.iloc[0][‘モデル’] best_mape = comparison.iloc[0][‘MAPE’] print(f”【推奨モデル】{best_model_name} (MAPE: {best_mape:.2f}%)”) print() # ============================================ # 可視化(横棒グラフ) # ============================================ fig, ax = plt.subplots(figsize=(12, 6)) models = comparison[‘モデル’] mapes = comparison[‘MAPE’] # plt.cm.RdYlGn_r: 赤→黄→緑のカラーマップ(反転) # 精度が高い(MAPE小)ほど緑、低いほど赤 colors = plt.cm.RdYlGn_r(np.linspace(0.2, 0.8, len(models))) # barh(): 横棒グラフ bars = ax.barh(models, mapes, color=colors, alpha=0.8, edgecolor=’black’) ax.set_xlabel(‘MAPE (%)’, fontsize=12) ax.set_title(‘予測モデル精度比較’, fontsize=14, fontweight=’bold’) ax.grid(axis=’x’, alpha=0.3) # 値を棒の右側に表示 for bar, mape in zip(bars, mapes): width = bar.get_width() ax.text(width + 0.3, bar.get_y() + bar.get_height()/2, f'{mape:.2f}%’, va=’center’, fontsize=11) plt.tight_layout() plt.show()

モデル選択のガイドライン

💡 状況に応じた手法の選び方
シンプルさ重視(経営層への説明):
→ Holt-Winters法
→ 「トレンド + 季節性」で直感的に説明
→ Excelでも実装可能

精度重視(在庫・人員計画):
→ ARIMA、Prophet
→ 統計的に厳密
→ 信頼区間も算出

季節性が強い(小売・観光):
→ Holt-Winters、Prophet
→ 季節パターンを自動検出

休日の影響が大きい:
→ Prophet
→ カスタム休日の設定が可能
→ GW、年末年始、お盆など

長期予測(1年以上):
→ Prophet
→ トレンド転換も考慮

データが少ない(1年未満):
→ 単純移動平均、SES
→ シンプルな手法が安定

📝 STEP 34 のまとめ

✅ このステップで学んだこと
  • 指数平滑法: 最新データを重視した予測
  • Holt-Winters法: トレンド + 季節性に対応
  • ARIMAモデル: 統計的に厳密な予測
  • Prophet: 実用的で使いやすいライブラリ
  • モデル比較: 複数手法を試して最適を選択
💡 実務での使い分け

状況に応じて最適な手法を選びましょう!

実務の鉄則:
必ず複数のモデルを試す
テストデータで精度を比較
過去データで最も精度が高いモデルを採用

モデル選択の優先順位:
1. まずHolt-Wintersを試す(シンプル)
2. 精度不足ならARIMAを試す(統計的)
3. 長期予測やイベント考慮ならProphet(柔軟)

注意点:
・どのモデルも「過去のパターンが続く」前提
・大きな環境変化には対応できない
・定期的にモデルを更新する必要あり

次のSTEP 35では、移動平均と季節調整を学びます!

📝 練習問題

問題 1 基礎

以下の状況に最適な時系列予測モデルを選んでください。

状況:
・アイスクリーム店の月次売上予測
・3年分のデータあり
・夏に売上が急増
・経営層へ説明が必要

選択肢:
A) 単純移動平均
B) Holt-Winters法
C) ARIMA(0,1,0)
D) ランダム予測

【解答】B) Holt-Winters法

理由:

1. 季節性が強い
・夏に売上急増 = 明確な季節パターン
・Holt-Winters法は季節性を考慮

2. 説明しやすい
・トレンド + 季節性 + 残差に分解
・経営層にも理解しやすい
・Excelでも実装可能

3. 実績がある
・小売業で広く使われる
・3年分のデータで十分学習可能

他の選択肢が不適切な理由:

A) 単純移動平均:
・季節性を考慮できない
・夏のピークを予測できない

C) ARIMA(0,1,0):
・季節性なしの設定
・ランダムウォークと同じ
・不適切

D) ランダム予測:
・論外

補足:
Prophetも良い選択肢!
・より柔軟
・休日(お盆など)も考慮可能
・ただし説明はHolt-Wintersの方が容易
問題 2 応用

ARIMAモデルのパラメータARIMA(p, d, q)について、
以下の設定の意味を説明してください。

ARIMA(2, 1, 1)の場合:
・p=2
・d=1
・q=1

それぞれ何を意味しますか?

【解答】

ARIMA(2, 1, 1)の意味:

p=2(自己回帰の次数)
・過去2期のデータを使用
・今月の値は先月と先々月の値から予測

式:
y_t = c + φ₁×y_{t-1} + φ₂×y_{t-2} + ε_t

例:
今月の売上 = 定数項
+ 係数1 × 先月の売上
+ 係数2 × 先々月の売上
+ 誤差

d=1(差分の次数)
・1階差分をとる
・トレンドを除去して定常化

差分:
y’_t = y_t – y_{t-1}

例:
今月の売上変化 = 今月 – 先月
100 → 110 → 105 の場合:
差分: +10, -5

q=1(移動平均の次数)
・過去1期の予測誤差を使用
・ランダムショックの影響を考慮

式:
ε_t = θ₁×ε_{t-1}

例:
前月の予測が外れた場合、
その誤差を今月の予測に反映

実務での解釈:

ARIMA(2,1,1)は:

1. トレンドがある(d=1)
・上昇または下降傾向
・差分で定常化

2. 過去2期の影響を受ける(p=2)
・先月と先々月の売上が重要
・短期的な依存性

3. ショックの影響が残る(q=1)
・前月の予測誤差を考慮
・一時的なイベントの影響

こんなデータに適用:
・成長トレンドあり
・前月・前々月の影響大
・一時的なイベント(セールなど)あり
問題 3 応用

以下の3つのモデルの予測結果があります。

テストデータ(6ヶ月)のMAPE:
・Holt-Winters: 8.5%
・ARIMA(1,1,1): 12.3%
・Prophet: 7.2%

どのモデルを採用すべきですか?
また、その理由を説明してください。

【解答】Prophet(MAPE: 7.2%)

理由:

1. 精度が最も高い
・Prophet: 7.2%(最小)
・Holt-Winters: 8.5%
・ARIMA: 12.3%

2. MAPEの評価
・7.2%は「良好」レベル(5〜10%)
・実務で十分活用できる精度

3. Prophetの追加メリット
・信頼区間も自動で算出
・休日の影響も考慮可能
・長期予測にも対応

ただし注意点:

状況によっては別の選択も:

Holt-Wintersを選ぶ場合:
・経営層への説明が重要
・Excelで実装したい
・MAPE差は1.3%程度なので許容範囲

検討すべきこと:
・テストデータが6ヶ月は少ない
・12ヶ月以上で再検証が望ましい
・季節性の1サイクル(12ヶ月)を含めたい

実務の推奨:
・Prophetをメインモデルとして採用
・Holt-Wintersをバックアップとして保持
・毎月精度をモニタリング
・精度が低下したらモデルを再検討

❓ よくある質問

Q1: Prophetとその他の手法、どう使い分けますか?
データの特性と目的で使い分けます。

Prophetを使うべき場合:
・複数年のデータがある(最低2年)
・季節性が強い
・休日の影響が大きい
・長期予測(1年以上)
・トレンド転換がありそう

Holt-Wintersを使うべき場合:
・シンプルさ重視
・経営層への説明が必要
・Excelで実装したい
・短期〜中期予測(3〜6ヶ月)

ARIMAを使うべき場合:
・統計的厳密性が必要
・信頼区間の算出が重要
・季節性が弱い
・学術的な報告

実務のコツ:
複数試して、精度が最も高いものを採用!
Q2: 予測精度が低い場合、どう改善しますか?
複数のアプローチで改善を試みます。

1. データの品質向上
・外れ値の処理
・欠損値の補完
・異常値の調整

2. 特徴量の追加
・休日フラグ
・プロモーション情報
・天候データ
・競合の動向

3. モデルの変更
・別の時系列モデルを試す
・機械学習モデル(XGBoost等)
・アンサンブル(複数モデルの組み合わせ)

4. パラメータ調整
・季節性の周期を変更
・平滑化パラメータ調整
・ARIMAの次数最適化

5. データ量の増加
・過去データを増やす
・類似商品のデータも使用
Q3: 信頼区間はどう解釈すればいいですか?
予測の不確実性を表す範囲です。

95%信頼区間の意味:
・真の値がこの範囲に入る確率95%
・例: 予測100万円 [80万〜120万]
・80万〜120万に収まる可能性95%

実務での活用:

リスク管理:
・下限値で在庫計画(欠品防止)
・上限値で人員計画(過剰対応防止)
・最悪・最良シナリオの策定

意思決定:
・信頼区間が広い → 不確実性大
・信頼区間が狭い → 予測が安定

経営層への報告:
「来月の売上は100万円と予測されますが、
80万〜120万の範囲になる可能性が95%です」

→ 不確実性を伝えることが重要!
Q4: 季節性が複数ある場合(週次+年次)はどうしますか?
Prophetが最も適しています。

複数季節性の例:
・週次: 土日に売上増
・月次: 月末に売上増
・年次: 12月に売上増

Prophetでの設定:
model = Prophet(
  yearly_seasonality=True,
  weekly_seasonality=True,
  daily_seasonality=False
)


カスタム季節性の追加:
model.add_seasonality(
  name='monthly',
  period=30.5,
  fourier_order=5
)


Holt-Wintersの場合:
・基本的に1つの季節性のみ
・複数対応は難しい
・データを週次集計して年次季節性を適用するなど工夫が必要
📝

学習メモ

ビジネスデータ分析・意思決定 - Step 34

📋 過去のメモ一覧
#artnasekai #学習メモ
LINE