LESSON

アンサンブル予測

「一つのモデルに頼るのは危険だ。複数のモデルを組み合わせることで、個々のモデルの弱点を補完できる。」

田中VPoEがKaggleのリーダーボードを表示する。

「上位入賞者のほとんどがアンサンブルを使っている。単純平均でもいいが、最適な重みを見つければさらに精度が上がる。」

アンサンブルの基本概念

アンサンブル予測:
  個別モデルの予測を組み合わせて、より正確な予測を生成する手法

利点:
  - バイアスの低減: 異なるバイアスを持つモデルが互いに打ち消す
  - 分散の低減: 複数予測の平均はノイズの影響が減る
  - ロバスト性: 1つのモデルが失敗しても全体への影響が限定的

アンサンブル手法の比較

手法方法複雑さ効果
単純平均全モデルの予測を等しく平均
加重平均バリデーション性能に基づく重み付き平均
メディアン予測値の中央値を採用中(外れ値に強い)
スタッキングメタモデルで予測を統合
ブレンディングホールドアウトセットで重みを学習

単純平均アンサンブル

import numpy as np
import pandas as pd

# 各モデルの予測結果を格納
predictions = {
    'sarima': sarima_forecast,
    'prophet': prophet_forecast,
    'lightgbm': lgbm_forecast,
}

# 単純平均
ensemble_simple = np.mean([predictions[m] for m in predictions], axis=0)

# 各モデルとアンサンブルの精度比較
from sklearn.metrics import mean_absolute_error

for name, pred in predictions.items():
    mae = mean_absolute_error(y_true, pred)
    print(f"{name:12s}: MAE = {mae:.2f}")

mae_ensemble = mean_absolute_error(y_true, ensemble_simple)
print(f"{'ensemble':12s}: MAE = {mae_ensemble:.2f}")

加重平均アンサンブル

バリデーションデータでの性能に基づいて重みを決定する。

from scipy.optimize import minimize

def weighted_ensemble(weights, predictions_list):
    """重み付きアンサンブル予測"""
    weighted = np.zeros_like(predictions_list[0])
    for w, pred in zip(weights, predictions_list):
        weighted += w * pred
    return weighted

def objective(weights, predictions_list, y_true):
    """最小化する目的関数(RMSE)"""
    pred = weighted_ensemble(weights, predictions_list)
    return np.sqrt(np.mean((pred - y_true) ** 2))

# バリデーションデータで最適重みを探索
predictions_list = [predictions['sarima'], predictions['prophet'], predictions['lightgbm']]
n_models = len(predictions_list)

# 初期値: 均等配分
initial_weights = np.ones(n_models) / n_models

# 制約: 重みの合計 = 1, 各重み >= 0
constraints = {'type': 'eq', 'fun': lambda w: np.sum(w) - 1}
bounds = [(0, 1)] * n_models

result = minimize(
    objective,
    initial_weights,
    args=(predictions_list, y_val),
    method='SLSQP',
    bounds=bounds,
    constraints=constraints
)

optimal_weights = result.x
print("最適重み:")
for name, w in zip(predictions.keys(), optimal_weights):
    print(f"  {name}: {w:.3f}")

# 最適重みでアンサンブル
ensemble_weighted = weighted_ensemble(optimal_weights, predictions_list)
mae_weighted = mean_absolute_error(y_true, ensemble_weighted)
print(f"\n加重平均アンサンブル MAE: {mae_weighted:.2f}")

スタッキング

1段目のモデルの予測を特徴量として、2段目のメタモデルで最終予測を行う。

from sklearn.linear_model import Ridge
from sklearn.model_selection import TimeSeriesSplit

# 1段目: 各モデルのOut-of-Fold予測を作成
tscv = TimeSeriesSplit(n_splits=5)
oof_predictions = np.zeros((len(X_train), n_models))

for fold, (train_idx, val_idx) in enumerate(tscv.split(X_train)):
    # 各モデルをfoldごとに学習し、val_idxの予測を格納
    for i, model_fn in enumerate(model_functions):
        model = model_fn()
        model.fit(X_train.iloc[train_idx], y_train.iloc[train_idx])
        oof_predictions[val_idx, i] = model.predict(X_train.iloc[val_idx])

# 2段目: メタモデル(Ridge回帰)の学習
meta_model = Ridge(alpha=1.0)
meta_model.fit(oof_predictions, y_train)

# テストデータでの予測
test_predictions = np.column_stack([
    predictions['sarima'],
    predictions['prophet'],
    predictions['lightgbm'],
])
ensemble_stacking = meta_model.predict(test_predictions)

print(f"スタッキング MAE: {mean_absolute_error(y_true, ensemble_stacking):.2f}")
print(f"メタモデルの係数: {meta_model.coef_}")

Store Salesでのアンサンブル戦略

# カテゴリ別にアンサンブル重みを変える戦略
# 理由: カテゴリによって最適なモデルが異なる

category_weights = {}

for family in train['family'].unique():
    family_val = y_val_per_family[family]
    family_preds = [pred_per_family[m][family] for m in predictions.keys()]

    result = minimize(
        objective,
        initial_weights,
        args=(family_preds, family_val),
        method='SLSQP',
        bounds=bounds,
        constraints=constraints
    )
    category_weights[family] = result.x

# 結果の例:
# GROCERY I:  SARIMA=0.1, Prophet=0.2, LightGBM=0.7
# BEVERAGES:  SARIMA=0.1, Prophet=0.3, LightGBM=0.6
# AUTOMOTIVE: SARIMA=0.4, Prophet=0.4, LightGBM=0.2
# → 安定カテゴリは統計モデル重視、変動大はLightGBM重視

アンサンブルの注意点

注意点説明
多様性似たモデルを組み合わせても効果が薄い
過学習バリデーションデータに重みを最適化しすぎると過学習
計算コストモデル数に比例して推論時間が増加
保守性本番運用ではシンプルなアンサンブルの方が安定

まとめ

項目ポイント
単純平均最もシンプルで効果的な第一歩
加重平均バリデーション性能で重みを最適化
スタッキングメタモデルで予測を統合。最も柔軟
戦略カテゴリ別に重みを変えるのが有効

チェックリスト

  • アンサンブルの3つの利点を説明できる
  • 加重平均の重みを最適化で求められる
  • スタッキングの2段構造を理解した
  • アンサンブルの注意点を把握した

次のステップへ

アンサンブル予測で精度を高めた。次は演習で実際にモデルを構築し、Kaggleスコアの改善に挑戦しよう。

推定読了時間: 30分