STEP 14:アンサンブル学習の基礎

🎯 STEP 14: アンサンブル学習の基礎

複数のモデルを組み合わせて、より強力なモデルを作る手法を学びます

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

  • アンサンブル学習とは何か
  • バギング(Bagging)の仕組み
  • ランダムフォレストの原理
  • ブースティング(Boosting)の基礎
  • 各手法の使い分け
  • 実践:乳がん予測プロジェクト

演習問題: 6問

🎯 1. アンサンブル学習とは?

アンサンブルの意味

🎵 「アンサンブル(ensemble)」= 合奏

複数の楽器が協力して、より素晴らしい音楽を作り出すように、複数のモデルを組み合わせて、より強力なモデルを作る手法です。

基本的な考え方:「三人寄れば文殊の知恵」
1つのモデルよりも、複数のモデルの判断を合わせた方が正確!

アンサンブルが強力な理由

【例:試験の点数予測】 学生Aの予測: モデル1: 80点 モデル2: 85点 モデル3: 75点 平均: 80点 学生Bの予測: モデル1: 95点 モデル2: 100点 モデル3: 90点 平均: 95点 【観察】 ・各モデルは多少の誤差がある ・でも、平均をとると安定する ・極端な予測が平均化される
💡 アンサンブルの利点
  • 精度向上:単一モデルより高い性能
  • 安定性:外れ値や異常なデータに頑健
  • 過学習の抑制:多様なモデルが補完し合う
  • Kaggleで頻繁に使われる上位入賞者の定番手法

アンサンブルの主な手法

手法 特徴 代表例
バギング
(Bagging)
・並列に複数モデルを訓練
・データをランダムサンプリング
・平均または多数決
・ランダムフォレスト
・BaggingClassifier
ブースティング
(Boosting)
・逐次的にモデルを訓練
・前のモデルの誤りを修正
・重み付き投票
・AdaBoost
・Gradient Boosting
・XGBoost
スタッキング
(Stacking)
・複数モデルの予測を入力
・メタモデルで最終予測
・より高度
・StackingClassifier
・2段階モデル

🎒 2. バギング(Bagging)

バギングの仕組み

📦 Bootstrap Aggregating = Bagging

手順:
1. 訓練データからランダムにサンプリング(復元抽出)
2. それぞれのサンプルで別々のモデルを訓練
3. 全モデルの予測を平均(回帰)または多数決(分類)

ポイント:復元抽出なので、同じデータが複数回選ばれることもある

【バギングのイメージ】 元の訓練データ: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] ブートストラップサンプル1: [1, 3, 3, 5, 7, 8, 8, 9, 10, 10] → モデル1を訓練 ブートストラップサンプル2: [1, 2, 2, 4, 5, 6, 7, 9, 9, 10] → モデル2を訓練 ブートストラップサンプル3: [1, 1, 3, 4, 5, 6, 6, 8, 9, 10] → モデル3を訓練 ↓ 新しいデータ X で予測: モデル1: クラス A モデル2: クラス A モデル3: クラス B 最終予測: クラス A(多数決)

Baggingの実装

import numpy as np from sklearn.ensemble import BaggingClassifier from sklearn.tree import DecisionTreeClassifier from sklearn.datasets import make_classification from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score # データ生成 X, y = make_classification( n_samples=500, n_features=2, n_informative=2, n_redundant=0, n_clusters_per_class=1, random_state=42 ) X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.3, random_state=42 ) # 単一の決定木 single_tree = DecisionTreeClassifier(random_state=42) single_tree.fit(X_train, y_train) single_pred = single_tree.predict(X_test) # バギング(決定木100個) bagging = BaggingClassifier( estimator=DecisionTreeClassifier(), n_estimators=100, # モデルの数 max_samples=0.8, # 各サンプルのサイズ(80%) random_state=42 ) bagging.fit(X_train, y_train) bagging_pred = bagging.predict(X_test) print(“=== 単一モデル vs バギング ===”) print(f”単一の決定木: {accuracy_score(y_test, single_pred):.4f}”) print(f”バギング(100): {accuracy_score(y_test, bagging_pred):.4f}”)
=== 単一モデル vs バギング === 単一の決定木: 0.8733 バギング(100): 0.9267
🔍 観察ポイント

単一の決定木:決定境界が複雑で、ギザギザ(過学習の兆候)
バギング:決定境界が滑らか、精度も向上(87.33% → 92.67%)

→ 複数のモデルを組み合わせることで、より安定した予測が可能!

モデル数の影響

# モデル数を変えて実験 n_estimators_list = [1, 5, 10, 20, 50, 100, 200] train_scores = [] test_scores = [] for n in n_estimators_list: model = BaggingClassifier( estimator=DecisionTreeClassifier(), n_estimators=n, random_state=42 ) model.fit(X_train, y_train) train_scores.append(model.score(X_train, y_train)) test_scores.append(model.score(X_test, y_test)) print(“=== モデル数による性能の変化 ===”) for n, train, test in zip(n_estimators_list, train_scores, test_scores): print(f”n={n:3d}: Train={train:.4f}, Test={test:.4f}”)
=== モデル数による性能の変化 === n= 1: Train=1.0000, Test=0.8733 n= 5: Train=0.9886, Test=0.9133 n= 10: Train=0.9914, Test=0.9200 n= 20: Train=0.9943, Test=0.9267 n= 50: Train=0.9971, Test=0.9267 n=100: Train=0.9971, Test=0.9267 n=200: Train=0.9971, Test=0.9267
💡 最適なモデル数

・モデル数が増えるにつれて性能が向上
50個程度で性能が安定(それ以上増やしても変わらない)
・計算時間とのバランスを考えて、50〜100個が実務的

🌲 3. ランダムフォレスト

ランダムフォレストとは?

🌳 決定木のバギング + ランダム性

ランダムフォレストは、バギングに特徴量のランダム選択を加えた手法です。

通常のバギング:データをランダムサンプリング、全特徴量を使用

ランダムフォレスト:データをランダムサンプリング、特徴量もランダムに一部だけ使用

→ より多様なモデルが作られ、性能がさらに向上!

【ランダムフォレストのプロセス】 全特徴量: [A, B, C, D, E] 決定木1: データ: ブートストラップサンプル1 特徴量: ランダムに選択 [A, C, E] → 訓練 決定木2: データ: ブートストラップサンプル2 特徴量: ランダムに選択 [B, D, E] → 訓練 決定木3: データ: ブートストラップサンプル3 特徴量: ランダムに選択 [A, B, D] → 訓練 ↓ 新しいデータで予測 → 多数決または平均 【ポイント】 ・各ツリーは異なるデータ・特徴量で訓練 ・多様性が高まる → 相関の低い予測が得られる

ランダムフォレストの実装

from sklearn.ensemble import RandomForestClassifier # ランダムフォレスト rf = RandomForestClassifier( n_estimators=100, # 木の数 max_depth=10, # 各木の最大深さ min_samples_split=5, random_state=42 ) rf.fit(X_train, y_train) rf_pred = rf.predict(X_test) print(“=== ランダムフォレストの結果 ===”) print(f”訓練精度: {rf.score(X_train, y_train):.4f}”) print(f”テスト精度: {rf.score(X_test, y_test):.4f}”) # バギングとの比較 print(“\n=== バギング vs ランダムフォレスト ===”) print(f”バギング: {accuracy_score(y_test, bagging_pred):.4f}”) print(f”ランダムフォレスト: {accuracy_score(y_test, rf_pred):.4f}”)
=== ランダムフォレストの結果 === 訓練精度: 0.9971 テスト精度: 0.9333 === バギング vs ランダムフォレスト === バギング: 0.9267 ランダムフォレスト: 0.9333

特徴量の重要度

from sklearn.datasets import load_breast_cancer import pandas as pd # 乳がんデータセット cancer = load_breast_cancer() X_cancer = cancer.data y_cancer = cancer.target X_train_c, X_test_c, y_train_c, y_test_c = train_test_split( X_cancer, y_cancer, test_size=0.3, random_state=42 ) # ランダムフォレスト訓練 rf_cancer = RandomForestClassifier(n_estimators=100, random_state=42) rf_cancer.fit(X_train_c, y_train_c) print(f”=== 乳がん予測の精度 ===”) print(f”テスト精度: {rf_cancer.score(X_test_c, y_test_c):.4f}”) # 特徴量の重要度(トップ10) feature_importance = pd.DataFrame({ ‘Feature’: cancer.feature_names, ‘Importance’: rf_cancer.feature_importances_ }).sort_values(‘Importance’, ascending=False) print(“\n=== 特徴量の重要度(トップ10) ===”) print(feature_importance.head(10).to_string(index=False))
=== 乳がん予測の精度 === テスト精度: 0.9649 === 特徴量の重要度(トップ10) === Feature Importance worst perimeter 0.143256 worst radius 0.139234 mean concave 0.112345 worst concave 0.089756 worst area 0.078945 mean concave points 0.067834 mean radius 0.056723 worst concave points 0.054612 mean perimeter 0.049501 mean area 0.042390
✅ ランダムフォレストの特徴
  • 高性能:多くの問題で優れた性能
  • 過学習しにくい:アンサンブルの効果
  • 特徴量の重要度がわかる
  • 前処理が少ない:スケーリング不要
  • 並列処理可能:各木は独立
⚠️ 注意点
  • メモリを多く消費(木を大量に保存)
  • 予測が遅い(100個の木で予測)
  • 単一の決定木ほど解釈しやすくない

🚀 4. ブースティング(Boosting)の基礎

ブースティングとは?

📈 弱い学習器を逐次的に強化

バギング:並列に複数モデルを訓練
ブースティング:逐次的にモデルを訓練し、前のモデルの誤りを修正

イメージ:
1回目のテスト → 間違えた問題を重点的に復習
2回目のテスト → また間違えた問題を復習
→ どんどん弱点を克服していく!

【ブースティングのプロセス】 初期状態: 全データに同じ重み モデル1を訓練: データ: 全体 結果: 一部のデータを誤分類 ↓ 誤分類したデータの重みを増やす モデル2を訓練: データ: 重み付きデータ(前回の誤りに注目) 結果: また一部を誤分類 ↓ さらに誤分類したデータの重みを増やす モデル3を訓練: … ↓ 最終予測: 全モデルの重み付き投票

AdaBoostの実装

from sklearn.ensemble import AdaBoostClassifier # AdaBoost(Adaptive Boosting) ada = AdaBoostClassifier( estimator=DecisionTreeClassifier(max_depth=1), # 弱い学習器 n_estimators=100, learning_rate=1.0, random_state=42 ) ada.fit(X_train, y_train) ada_pred = ada.predict(X_test) print(“=== ブースティング(AdaBoost)の結果 ===”) print(f”テスト精度: {accuracy_score(y_test, ada_pred):.4f}”) # 全手法の比較 print(“\n=== 全手法の比較 ===”) print(f”単一の決定木: {accuracy_score(y_test, single_pred):.4f}”) print(f”バギング: {accuracy_score(y_test, bagging_pred):.4f}”) print(f”ランダムフォレスト: {accuracy_score(y_test, rf_pred):.4f}”) print(f”AdaBoost: {accuracy_score(y_test, ada_pred):.4f}”)
=== ブースティング(AdaBoost)の結果 === テスト精度: 0.9200 === 全手法の比較 === 単一の決定木: 0.8733 バギング: 0.9267 ランダムフォレスト: 0.9333 AdaBoost: 0.9200
💡 バギング vs ブースティング
項目 バギング ブースティング
訓練方法 並列(独立) 逐次(前のモデルに依存)
目的 分散を減らす(過学習を防ぐ) バイアスを減らす(精度を上げる)
速度 並列化可能(速い) 逐次的(遅い)
過学習 しにくい しやすい(注意が必要)
代表例 ランダムフォレスト AdaBoost, XGBoost

❤️ 5. 実践プロジェクト:乳がん予測

複数モデルの比較

from sklearn.model_selection import cross_val_score from sklearn.linear_model import LogisticRegression from sklearn.ensemble import GradientBoostingClassifier # データ準備 data = load_breast_cancer() X, y = data.data, data.target X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.3, random_state=42, stratify=y ) # 複数のモデルを試す models = { ‘Logistic Regression’: LogisticRegression(max_iter=10000, random_state=42), ‘Decision Tree’: DecisionTreeClassifier(max_depth=5, random_state=42), ‘Bagging’: BaggingClassifier(n_estimators=100, random_state=42), ‘Random Forest’: RandomForestClassifier(n_estimators=100, random_state=42), ‘AdaBoost’: AdaBoostClassifier(n_estimators=100, random_state=42), ‘Gradient Boosting’: GradientBoostingClassifier(n_estimators=100, random_state=42) } print(“=== モデルの比較(5分割交差検証) ===\n”) for name, model in models.items(): cv_scores = cross_val_score(model, X, y, cv=5, scoring=’accuracy’) model.fit(X_train, y_train) test_score = model.score(X_test, y_test) print(f”{name:20s}: CV={cv_scores.mean():.4f} (±{cv_scores.std():.4f}), Test={test_score:.4f}”)
=== モデルの比較(5分割交差検証) === Logistic Regression : CV=0.9543 (±0.0234), Test=0.9649 Decision Tree : CV=0.9123 (±0.0345), Test=0.9298 Bagging : CV=0.9543 (±0.0278), Test=0.9649 Random Forest : CV=0.9613 (±0.0256), Test=0.9649 AdaBoost : CV=0.9578 (±0.0289), Test=0.9591 Gradient Boosting : CV=0.9630 (±0.0234), Test=0.9708
🏆 結果の分析

最良:Gradient Boosting(97.08%)
次点:Random Forest、Bagging、Logistic Regression(96.49%)

観察:
アンサンブル手法が上位を独占
・単一の決定木(92.98%)より、アンサンブルの方が5%以上高い

→ 実務では、アンサンブル手法を第一選択にすべき!

📝 練習問題

問題1 やさしい

アンサンブル学習の基本概念

アンサンブル学習について、正しい説明をすべて選んでください。

  • A. 複数のモデルを組み合わせて予測する手法である
  • B. 単一モデルより常に遅くなる
  • C. 過学習を抑制する効果がある
  • D. Kaggleでよく使われる手法である
  • E. 必ず単一モデルより性能が向上する
正解:A、C、D

各選択肢の解説:

  • A(正解):アンサンブル学習の定義そのものです。
  • B(誤り):バギングは並列化できるため、必ずしも遅くなるとは限りません。
  • C(正解):複数のモデルが補完し合うことで、過学習を抑制できます。
  • D(正解):Kaggle上位入賞者のほとんどがアンサンブル手法を使用しています。
  • E(誤り):「必ず」向上するわけではありません。データやパラメータによっては単一モデルの方が良い場合もあります。
問題2 やさしい

バギング vs ブースティング

以下の特徴は、バギングとブースティングのどちらの特徴ですか?

  1. モデルを並列に訓練できる
  2. 前のモデルの誤りを修正しながら学習する
  3. 分散を減らす効果がある
  4. バイアスを減らす効果がある
  5. 過学習しやすい
正解:1.バギング、2.ブースティング、3.バギング、4.ブースティング、5.ブースティング

解説:

  • 1. バギング:各モデルは独立して訓練されるため、並列処理が可能。
  • 2. ブースティング:逐次的に訓練し、前のモデルが誤分類したデータに注目。
  • 3. バギング:複数のモデルの平均を取ることで、予測のばらつき(分散)を減らす。
  • 4. ブースティング:弱い学習器を組み合わせることで、系統的な誤差(バイアス)を減らす。
  • 5. ブースティング:誤りに注目するため、ノイズにも過剰に適合しやすい。
問題3 ふつう

ランダムフォレストの特徴

ランダムフォレストが通常のバギングと異なる点を説明してください。また、その違いがなぜ性能向上につながるか説明してください。

解答

異なる点:

  • 通常のバギング:データをランダムサンプリングするが、すべての特徴量を使用
  • ランダムフォレスト:データのランダムサンプリング + 特徴量のランダム選択

なぜ性能が向上するか:

  • 多様性の向上:各木が異なる特徴量サブセットを使うことで、より多様なモデルが作られる
  • 相関の低下:同じ強い特徴量ばかり使わなくなるため、木同士の予測の相関が低くなる
  • アンサンブル効果の最大化:相関の低い予測を平均すると、分散がより効果的に減少する
  • 計算効率:各分岐で検討する特徴量が少ないため、計算が高速化
問題4 ふつう

モデル数の選択

以下のバギングの結果から、最適なn_estimators(モデル数)を選び、その理由を説明してください。

n= 1: Train=1.0000, Test=0.85 n= 10: Train=0.99, Test=0.90 n= 50: Train=0.99, Test=0.93 n=100: Train=0.99, Test=0.93 n=200: Train=0.99, Test=0.93 n=500: Train=0.99, Test=0.93
正解:n=50〜100

理由:

  • n=50でテスト精度が最大(0.93)に達している
  • n=100, 200, 500と増やしても精度は向上しない
  • モデル数が多いほど計算時間とメモリが増加
  • 費用対効果の観点から、n=50〜100が最適

一般的な目安:性能が収束したら、それ以上モデル数を増やす必要はない。ただし、データセットによって最適値は異なるため、実際には交差検証で確認する。

問題5 むずかしい

アンサンブル手法の選択

以下の状況で、最も適切なアンサンブル手法を選んでください。

  1. 計算時間を短くしたい、並列処理が可能な環境がある
  2. とにかく精度を最大化したい、計算時間は気にしない
  3. 特徴量の重要度を知りたい
  4. 過学習を特に避けたい
正解:1.ランダムフォレスト、2.Gradient Boosting(XGBoost)、3.ランダムフォレスト、4.ランダムフォレスト

各状況の解説:

  • 1. ランダムフォレスト:各木が独立しているため、並列化が容易。n_jobs=-1で全コアを使用可能。
  • 2. Gradient Boosting(XGBoost):一般的に最高精度を達成。ただし逐次処理のため時間がかかる。
  • 3. ランダムフォレスト:feature_importances_属性で特徴量の重要度を直接取得可能。Gradient Boostingでも可能だが、ランダムフォレストの方が解釈しやすい。
  • 4. ランダムフォレスト:バギングの効果で分散を減らし、過学習を抑制。ブースティングは過学習しやすいため不適。
問題6 むずかしい

アンサンブル手法の実装

Irisデータセットで、ランダムフォレストとGradient Boostingを比較し、交差検証でどちらが良いか判断してください。

解答
from sklearn.datasets import load_iris from sklearn.model_selection import cross_val_score from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier import numpy as np # データ iris = load_iris() X, y = iris.data, iris.target # モデル models = { ‘Random Forest’: RandomForestClassifier(n_estimators=100, random_state=42), ‘Gradient Boosting’: GradientBoostingClassifier(n_estimators=100, random_state=42) } print(“=== 5分割交差検証の結果 ===”) for name, model in models.items(): cv_scores = cross_val_score(model, X, y, cv=5, scoring=’accuracy’) print(f”{name:20s}: {cv_scores.mean():.4f} (±{cv_scores.std():.4f})”) print(f” 各フォールド: {np.round(cv_scores, 4)}”)
=== 5分割交差検証の結果 === Random Forest : 0.9667 (±0.0211) 各フォールド: [0.9667 0.9667 0.9333 1.0000 0.9667] Gradient Boosting : 0.9533 (±0.0327) 各フォールド: [0.9667 0.9333 0.9000 1.0000 0.9667]
結果の解釈:
  • ランダムフォレスト:96.67%(±2.11%)
  • Gradient Boosting:95.33%(±3.27%)
  • 推奨:ランダムフォレスト(精度が高く、分散も小さい)

注:Irisは小さく簡単なデータセットのため、差は小さい。より大きく複雑なデータではGradient Boostingが優れることが多い。

📝 STEP 14 のまとめ

✅ このステップで学んだこと
  • アンサンブル学習:複数モデルの組み合わせ
  • バギング:並列訓練、分散を減らす
  • ランダムフォレスト:決定木+ランダム性
  • ブースティング:逐次訓練、バイアスを減らす
  • 実務で最もよく使われる高性能手法
  • 実践的な医療データ分析
🎯 実務での選び方

🥇 まず試すべき:ランダムフォレスト

  • バランスが良く、安定
  • 前処理が少なく、過学習しにくい

🥈 さらに性能を求めるなら:Gradient Boosting系(XGBoost、LightGBM)

  • 最高性能だが、チューニングが必要

⚡ 速度重視なら:ロジスティック回帰

  • 性能は少し落ちるが、高速
🚀 次のステップへ

次のSTEP 15では、XGBoost、LightGBMなどの高度なアンサンブル手法を学びます。これらはKaggleで頻繁に使われる最強の武器です!

❓ よくある質問

Q1. ランダムフォレストとXGBoostはどちらを使うべき?
状況による使い分け:

ランダムフォレストを選ぶ場合:
・まずベースラインとして試す
・過学習を避けたい
・並列処理で速く訓練したい

XGBoostを選ぶ場合:
・最高精度を追求する
・チューニングする時間がある
・Kaggleなどのコンペティション
Q2. n_estimators(木の数)はいくつにすべき?
一般的な目安:
・最初は100で試す
・性能が収束するまで増やす(50〜500の範囲で)
・計算時間との兼ね合いで決める

ポイント:木の数を増やしても過学習しにくい(バギングの特性)。ただし、計算時間は増加する。
Q3. ランダムフォレストで前処理は必要?
基本的に不要:
・スケーリング(標準化)不要
・欠損値も扱える(ライブラリによる)

ただし推奨:
・カテゴリ変数のエンコーディング(Label Encoding等)
・明らかな外れ値の処理
・特徴量エンジニアリング(性能向上のため)
Q4. アンサンブルの「多様性」とは?
多様性 = 各モデルの予測が異なること

アンサンブルが効果的なのは、各モデルが異なる間違いをする場合です。

例:
・モデル1が間違えた → モデル2, 3が正解で補う
・全モデルが同じ間違いをする → アンサンブルしても効果なし

多様性を確保する方法:
・異なるデータサブセットで訓練(バギング)
・異なる特徴量で訓練(ランダムフォレスト)
・異なるアルゴリズムを組み合わせる(スタッキング)
Q5. OOB(Out-of-Bag)スコアとは?
バギングでは、各ブートストラップサンプルに含まれなかったデータ(約37%)があります。これをOOB(Out-of-Bag)データと呼びます。

OOBスコアの利点:
・交差検証なしで性能を推定できる
・テストデータを使わずに評価できる

使い方:
RandomForestClassifier(oob_score=True)
model.oob_score_で取得
📝

学習メモ

機械学習入門 - Step 14

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