📚 背景知識(読んでから問題へ)
🏆
Day 081 でロジスティック回帰ベースライン(CV ≈ 0.80)を作り、Day 082 で特徴量エンジニアリングを追加(CV ≈ 0.82〜0.83)しました。
今日はアンサンブルを使い、Titanic のリーダーボード上位25%(スコア ≈ 0.80以上)を目指します。
💡
アンサンブルとは「複数の専門家の意見を組み合わせる」手法です。1つのモデルより多数のモデルを組み合わせる方が、偏った判断ミスを相殺できます。
3つのモデルの役割分担
| モデル | 強み | 弱み | 期待CV |
|---|---|---|---|
LogisticRegression |
安定・高速・線形関係の捉え方 | 非線形を苦手とする | ≈ 0.81 |
RandomForestClassifier |
特徴量間の交互作用を捉える | 深い木は過学習しやすい | ≈ 0.82 |
GradientBoostingClassifier |
残差を逐次学習・高精度 | 計算コストが高い | ≈ 0.83 |
| VotingClassifier (soft) | 各モデルの誤りを補完 | 遅い・ハイパーパラメータ増 | ≈ 0.83〜0.84 |
① 特徴量エンジニアリング(Day082)
→
② sklearn Pipeline
→
③ VotingClassifier
→
④ Soft Voting
→
⑤ Stratified K-Fold CV
→
⑥ submission.csv
🗳️ Soft Voting の仕組み
ある乗客 X に対して3モデルが「生存確率」を予測した場合:
Logistic Regression
0.72
生存確率
+
Random Forest
0.81
生存確率
+
Gradient Boosting
0.65
生存確率
→
平均確率
0.727
閾値0.5超 → 生存(1)
📌
Hard Voting との違い:
Hard Voting は「1, 1, 1 → 生存(多数決)」と各モデルのクラスだけ見ます。
Soft Voting は確率の平均で決定するため、モデルの「自信度」が反映されより高精度です。
Hard Voting は「1, 1, 1 → 生存(多数決)」と各モデルのクラスだけ見ます。
Soft Voting は確率の平均で決定するため、モデルの「自信度」が反映されより高精度です。
重み付き Soft Voting: weights=[1, 2, 2] の場合
📋 アンサンブル手法比較
| 手法 | 概要 | 実装難易度 | 精度向上 | 計算コスト |
|---|---|---|---|---|
| Hard Voting | クラスの多数決 | 簡単 | 中 | 低 |
| Soft Voting | 確率の平均 | 簡単 | 中〜高 | 低 |
| Averaging | Soft Voting の連続値版(回帰) | 簡単 | 中 | 低 |
| Stacking | Level-1予測を Level-2モデルに渡す | 普通 | 高 | 中〜高 |
| Blending | hold-out でメタ特徴量を作成 | 普通 | 高 | 中 |
🎯 問題
📋
要件1: 前処理パイプラインを再構築
Day 082 の特徴量(Title / FamilySize / IsAlone / Deck)をすべて含める。
Day 082 の特徴量(Title / FamilySize / IsAlone / Deck)をすべて含める。
📋
要件2: 3つのモデルを定義
・
・
・
・
LogisticRegression(max_iter=1000)・
RandomForestClassifier(n_estimators=200)・
GradientBoostingClassifier(n_estimators=200, learning_rate=0.05)
📋
要件3: VotingClassifier(soft voting)でアンサンブル
voting='soft'、weights=[1, 2, 2] で RF・GB を重視する。
📋
要件4: Stratified K-Fold CV(k=5)でスコア計測
各モデル単体と Voting のスコアを表示し、Voting が最高になることを確認する。
各モデル単体と Voting のスコアを表示し、Voting が最高になることを確認する。
📋
要件5: Kaggle提出ファイルを生成
submission.csv(PassengerId, Survived)を出力する。
💡 ヒント
Hint 1
方向性
VotingClassifier は estimators=[('lr', lr), ('rf', rf), ('gb', gb)] のようにリストで渡す。
Hint 2
アプローチ
soft voting を使うには各モデルが predict_proba をサポートしている必要がある。LR は max_iter=1000 で収束しやすくなる。
Hint 3
コード骨格
from sklearn.ensemble import VotingClassifier, RandomForestClassifier, GradientBoostingClassifier from sklearn.linear_model import LogisticRegression lr = LogisticRegression(max_iter=1000, C=1.0) rf = RandomForestClassifier(n_estimators=200, random_state=42) gb = GradientBoostingClassifier(n_estimators=200, learning_rate=0.05, random_state=42) voting = VotingClassifier( estimators=[('lr', lr), ('rf', rf), ('gb', gb)], voting='soft' ) from sklearn.model_selection import cross_val_score, StratifiedKFold cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42) for name, model in [('LR', lr), ('RF', rf), ('GB', gb), ('Voting', voting)]: scores = cross_val_score(model, X, y, cv=cv, scoring='accuracy') print(f"{name}: {scores.mean():.4f} ± {scores.std():.4f}")
✅ 模範解答
import pandas as pd import numpy as np from sklearn.pipeline import Pipeline from sklearn.preprocessing import StandardScaler, OneHotEncoder from sklearn.compose import ColumnTransformer from sklearn.impute import SimpleImputer from sklearn.linear_model import LogisticRegression from sklearn.ensemble import (RandomForestClassifier, GradientBoostingClassifier, VotingClassifier) from sklearn.model_selection import cross_val_score, StratifiedKFold # ── 1. データ読み込み ────────────────────────────── train = pd.read_csv('train.csv') test = pd.read_csv('test.csv') # ── 2. 特徴量エンジニアリング(Day 082 の成果)──────── def engineer_features(df): df = df.copy() df['Title'] = df['Name'].str.extract(r',\s*([^\.]+)\.') rare = ['Jonkheer','Don','Sir','Capt','Col','Major','Rev', 'Dr','Lady','Countess','Mme','Ms','Mlle','the Countess','Dona'] df['Title'] = df['Title'].replace(rare, 'Rare') df['FamilySize'] = df['SibSp'] + df['Parch'] + 1 df['IsAlone'] = (df['FamilySize'] == 1).astype(int) df['Deck'] = df['Cabin'].str[0].fillna('U') return df train = engineer_features(train) test = engineer_features(test) # ── 3. 特徴量選択 ────────────────────────────────── features_num = ['Age', 'Fare', 'FamilySize'] features_cat = ['Pclass', 'Sex', 'Embarked', 'Title', 'Deck', 'IsAlone'] X = train[features_num + features_cat] y = train['Survived'] X_test = test[features_num + features_cat] # ── 4. 前処理パイプライン ───────────────────────── num_pipe = Pipeline([ ('impute', SimpleImputer(strategy='median')), ('scale', StandardScaler()), ]) cat_pipe = Pipeline([ ('impute', SimpleImputer(strategy='constant', fill_value='Missing')), ('ohe', OneHotEncoder(handle_unknown='ignore', sparse_output=False)), ]) preprocessor = ColumnTransformer([ ('num', num_pipe, features_num), ('cat', cat_pipe, features_cat), ]) # ── 5. モデル定義 ──────────────────────────────── lr = LogisticRegression(max_iter=1000, C=1.0, random_state=42) rf = RandomForestClassifier(n_estimators=200, max_depth=6, min_samples_leaf=4, random_state=42) gb = GradientBoostingClassifier(n_estimators=200, learning_rate=0.05, max_depth=3, random_state=42) voting = VotingClassifier( estimators=[('lr', lr), ('rf', rf), ('gb', gb)], voting='soft', weights=[1, 2, 2], ) # ── 6. CV評価 ────────────────────────────────────── cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42) results = {} for name, base_model in [('LR', lr), ('RF', rf), ('GB', gb), ('Voting', voting)]: pipe = Pipeline([('prep', preprocessor), ('model', base_model)]) scores = cross_val_score(pipe, X, y, cv=cv, scoring='accuracy') results[name] = scores print(f"{name:8s}: {scores.mean():.4f} ± {scores.std():.4f}") # ── 7. 最終モデルで全訓練データ学習 → 提出ファイル ───── final_pipe = Pipeline([('prep', preprocessor), ('model', voting)]) final_pipe.fit(X, y) preds = final_pipe.predict(X_test) submission = pd.DataFrame({'PassengerId': test['PassengerId'], 'Survived': preds}) submission.to_csv('submission.csv', index=False) print("\nsubmission.csv を生成しました!") print(submission['Survived'].value_counts())
🔢 Step-by-Step 解説
1
特徴量エンジニアリング関数をまとめる
def engineer_features(df) として関数化することで、train と test の両方に同じ処理を適用できます。
関数化しないと test データに特徴量を作り忘れるバグが頻発します(Kaggleでよくあるミス)。
↓
2
3つのモデルを準備する
各パラメータの意味:
・
・
・
・
各パラメータの意味:
・
max_iter=1000: LR の収束まで最大1000回計算・
n_estimators=200: RF/GB は木200本を作る・
learning_rate=0.05: GB はゆっくり慎重に学習(過学習防止)・
max_depth=6/3: 木の深さを制限(過学習防止)
↓
3
VotingClassifier を組み立てる
VotingClassifier( estimators=[('lr', lr), ('rf', rf), ('gb', gb)], voting='soft', weights=[1, 2, 2], )
voting='soft': 確率の平均(hard=多数決より精度が良い)weights=[1, 2, 2]: RF・GB を2倍重視(LR より性能が高いため)
↓
4
Pipeline + CV でリーク防止評価
Pipeline([('prep', preprocessor), ('model', voting)]) として前処理→モデルを一体化。
これで「CVの各フォールドで前処理を独立して行う」ため情報リークが起きません。
↓
5
全訓練データで再学習 → 提出ファイル生成
CV評価後、
CV評価後、
final_pipe.fit(X, y) で全データを使って最終モデルを学習。
predict(X_test) で test の予測を生成し submission.csv に保存します。
📈 精度比較チャート(期待値)
CV Accuracy(5-Fold Stratified、Day 082 特徴量使用)
LR(ベースライン)
≈ 0.810
ベースライン
RandomForest
≈ 0.820
単体
GradientBoosting
≈ 0.830
単体
Voting (soft, w=[1,2,2])
≈ 0.838
最良
※ 実際のスコアは乱数・特徴量の実装によって変動します。アンサンブルは必ずしも単体を上回るとは限りません。
Titanic リーダーボード目安(Public LB Accuracy)
📐 数学補足(文系向け)
Soft Voting の計算式
📌
重み付き平均確率:
今日の例: weights=[1, 2, 2]、各モデル確率=[0.72, 0.81, 0.65]
0.728 > 0.5 → 生存(1)と予測
P_final = (w₁×P₁ + w₂×P₂ + w₃×P₃) / (w₁ + w₂ + w₃)今日の例: weights=[1, 2, 2]、各モデル確率=[0.72, 0.81, 0.65]
P_final = (1×0.72 + 2×0.81 + 2×0.65) / 5 = (0.72 + 1.62 + 1.30) / 5 = 3.64 / 5 = 0.7280.728 > 0.5 → 生存(1)と予測
なぜアンサンブルが効くのか(分散の削減)
💡
各モデルの誤りが互いに独立していれば、平均を取ることで分散(ブレ)が減ります。
コインを1枚投げると裏表の確率は不安定ですが、100枚投げれば表は約50%に安定します。アンサンブルも同じ原理です。
コインを1枚投げると裏表の確率は不安定ですが、100枚投げれば表は約50%に安定します。アンサンブルも同じ原理です。
🏅 Kaggleでの実践的な使い方
| 状況 | 推奨手法 |
|---|---|
| まず試す | Soft Voting(実装が簡単、安定した向上が期待できる) |
| 精度を極める | Stacking(Level-2 メタモデル)→ Phase 4 テーマ13-15 |
| 計算リソースが限られる | Hard Voting or Averaging(高速) |
| 上位1%を目指す | 5〜10モデルの Stacking + Pseudo Labeling |
⚠️
Titanic では Voting / Stacking で 0.79〜0.81 が現実的な目標です。
0.82以上は強力な特徴量工学が必要で、トップ1%(≈ 0.84)は既知リークを活用することが多いです。
CVスコアを信頼し、LBスコアに過度に合わせないことがKaggleの基本原則です。
⚠️ よくある誤解・ミス
| 誤解・ミス | なぜ起こるか | 正しい理解 |
|---|---|---|
| モデルを増やせば必ず精度が上がる | アンサンブルの誤解 | 相関の低い多様なモデルを組み合わせることが重要。同じ種類を増やしても効果は薄い |
| soft voting で predict_proba エラー | SVM など確率を返さないモデルを使用 | SVM は probability=True が必要。sklearn の大半のモデルは対応済み |
| test データに特徴量工学を忘れる | train にしか処理しない | engineer_features 関数化し train・test 両方に適用する |
| CV と Pipeline を分離してリーク発生 | 前処理を先にやってから CV | Pipeline に前処理を含め cross_val_score に渡す |
| weights をむやみに大きくする | 性能の良いモデルを過度に重視 | CVスコアの差が小さい場合は均等重みの方が安定することもある |
🚀 次のステップ
📖
発展: Stacking(Level-2 メタモデル)
VotingClassifier の上位版。Level-1の予測確率を新しい特徴量として Level-2 モデル(LR など)に学習させる。 さらに 1〜2% の精度向上が期待できる。→ Phase 4 テーマ13-15 で詳しく学ぶ。
VotingClassifier の上位版。Level-1の予測確率を新しい特徴量として Level-2 モデル(LR など)に学習させる。 さらに 1〜2% の精度向上が期待できる。→ Phase 4 テーマ13-15 で詳しく学ぶ。
🎯
次回予告: Playground Series 活用法
Kaggle の月次コンペ(Playground Series)を使って、実際にコンペに参加しながら Bronze → Silver メダルを狙う戦略を学ぶ。
Kaggle の月次コンペ(Playground Series)を使って、実際にコンペに参加しながら Bronze → Silver メダルを狙う戦略を学ぶ。
📝 自己評価(解いた後に記入)
自分の回答・気づき・メモ: