LESSON

オーバーフィッティング対策

田中VPoE:「モデルの精度を上げようとして複雑にしすぎると、学習データにだけ特化してしまう。これが過学習だ。実運用では新しいデータに対する予測が重要だから、過学習への対策は必須だ。」

あなた:「前に学んだ正則化以外にも対策があるんですか?」

田中VPoE:「たくさんある。Early Stopping、特徴量削減、データ拡張、ドロップアウトなど、状況に応じて使い分ける。今日はこれらを体系的に学ぼう。」

過学習の検出

まず、過学習が起きているかを正しく検出することが重要です。

from sklearn.model_selection import cross_validate
from sklearn.ensemble import RandomForestClassifier

model = RandomForestClassifier(n_estimators=200, max_depth=None, random_state=42)

cv_results = cross_validate(
    model, X_train, y_train,
    cv=5, scoring='f1',
    return_train_score=True,
)

train_mean = cv_results['train_score'].mean()
val_mean = cv_results['test_score'].mean()
gap = train_mean - val_mean

print(f"学習スコア: {train_mean:.3f}")
print(f"検証スコア: {val_mean:.3f}")
print(f"ギャップ:   {gap:.3f}")

if gap > 0.1:
    print("→ 過学習の兆候あり!対策が必要です。")
elif gap < 0.02:
    print("→ 良好。過学習は見られません。")
else:
    print("→ 軽度の過学習。改善の余地があります。")

対策1: 正則化

線形モデルの正則化

from sklearn.linear_model import LogisticRegression

# C を小さくすることで強い正則化
for C in [0.001, 0.01, 0.1, 1.0, 10.0]:
    model = LogisticRegression(C=C, max_iter=1000, random_state=42)
    cv = cross_validate(model, X_train_scaled, y_train, cv=5,
                       scoring='f1', return_train_score=True)
    print(f"C={C:>5}: 学習={cv['train_score'].mean():.3f}, "
          f"検証={cv['test_score'].mean():.3f}, "
          f"差={cv['train_score'].mean()-cv['test_score'].mean():.3f}")

木モデルの正則化

from sklearn.ensemble import RandomForestClassifier

# max_depth, min_samples_leaf で複雑度を制限
for depth in [3, 5, 10, 15, None]:
    model = RandomForestClassifier(max_depth=depth, n_estimators=100, random_state=42)
    cv = cross_validate(model, X_train, y_train, cv=5,
                       scoring='f1', return_train_score=True)
    print(f"max_depth={str(depth):>4}: 学習={cv['train_score'].mean():.3f}, "
          f"検証={cv['test_score'].mean():.3f}")

対策2: Early Stopping

学習を途中で止めることで、モデルが学習データに過度に適合するのを防ぎます。

import lightgbm as lgb

model = lgb.LGBMClassifier(
    n_estimators=1000,  # 十分大きく設定
    learning_rate=0.05,
    random_state=42,
    verbose=-1,
)

model.fit(
    X_train, y_train,
    eval_set=[(X_val, y_val)],
    callbacks=[
        lgb.early_stopping(stopping_rounds=50),  # 50ラウンド改善なしで停止
        lgb.log_evaluation(0),
    ],
)

print(f"最適なイテレーション数: {model.best_iteration_}")
print(f"最適なスコア: {model.best_score_['valid_0']['binary_logloss']:.4f}")

Early Stopping の仕組み

イテレーション   学習Loss   検証Loss   状態
1               0.500      0.520      改善中
50              0.200      0.250      改善中
100             0.100      0.230      ← 検証Lossが最小
150             0.050      0.250      改善なし(50ラウンド)
→ イテレーション100で停止

対策3: 特徴量の削減

不要な特徴量を除外して、モデルの複雑度を下げます。

from sklearn.feature_selection import SelectFromModel

# 重要度が低い特徴量を除外
selector = SelectFromModel(
    RandomForestClassifier(n_estimators=100, random_state=42),
    threshold='median',  # 中央値以上の重要度を持つ特徴量を選択
)

selector.fit(X_train, y_train)
X_train_selected = selector.transform(X_train)
X_val_selected = selector.transform(X_val)

print(f"元の特徴量数: {X_train.shape[1]}")
print(f"選択後の特徴量数: {X_train_selected.shape[1]}")

# 選択された特徴量で再評価
model_selected = RandomForestClassifier(n_estimators=100, random_state=42)
cv_selected = cross_validate(model_selected, X_train_selected, y_train,
                            cv=5, scoring='f1', return_train_score=True)
print(f"検証F1: {cv_selected['test_score'].mean():.3f}")

対策4: データの増量

データが少ない場合、データの量を増やすことが最も効果的です。

# SMOTE(Synthetic Minority Over-sampling Technique)
# 少数クラスの合成サンプルを生成
from imblearn.over_sampling import SMOTE

smote = SMOTE(random_state=42)
X_train_resampled, y_train_resampled = smote.fit_resample(X_train, y_train)

print(f"リサンプリング前: {pd.Series(y_train).value_counts().to_dict()}")
print(f"リサンプリング後: {pd.Series(y_train_resampled).value_counts().to_dict()}")

対策の選択ガイド

過学習の程度推奨対策
軽度(差 < 0.05)max_depth 調整、min_samples_leaf 増加
中度(差 0.05-0.15)正則化強化、特徴量削減、Early Stopping
重度(差 > 0.15)モデル簡素化、データ増量、アンサンブル

実践的なチェックリスト

# 過学習対策のステップ
steps = [
    "1. 学習曲線で過学習を確認",
    "2. max_depth / min_samples_leaf を調整",
    "3. 正則化パラメータを強化(C↓, alpha↑)",
    "4. Early Stopping を適用",
    "5. 不要な特徴量を削除",
    "6. データが少なければ増量を検討",
    "7. よりシンプルなモデルに変更を検討",
]
for step in steps:
    print(step)

まとめ

  • 過学習は学習/検証スコアのギャップで検出する
  • 正則化: モデルの複雑度にペナルティを与える
  • Early Stopping: 検証スコアが改善しなくなったら学習を停止
  • 特徴量削減: 不要な特徴量を除外して複雑度を下げる
  • データ増量: SMOTE 等で少数クラスのサンプルを増やす
  • 対策は段階的に適用し、効果を確認しながら進める

チェックリスト

  • 過学習の検出方法を実践できる
  • 正則化パラメータの調整方法を理解した
  • Early Stopping の仕組みと設定方法を把握した
  • 状況に応じた対策の選択ができる

次のステップへ

次のレッスンでは、ハイパーパラメータ最適化の手法を学びます。GridSearch からベイジアン最適化まで、効率的にモデルを改善する方法を身につけましょう。


推定読了時間: 30分