忍者ブログ
統計、機械学習、AIを学んでいきたいと思います。 お役に立てば幸いです。

【Kaggle挑戦記】Titanic 攻略 #13:自己ベスト更新 0.78468!「引き算」と「新しい視点」の勝利

前回(攻略 #12)では、精緻に作り込んだ「敬称」データがまさかの裏目に出て、スコアが 0.77751 まで下落するという苦い経験をしました。しかし、その敗北から学んだ「情報の重複を削る」という教訓、そして新たな物理的要因 Embarked(乗船港) の導入が、ついに 0.78468 という自己ベスト更新を呼び込みました!

1. 逆転の戦略:複雑さを捨て、文脈を足す

今回の成功のポイントは、単なる「足し算」ではなく、勇気を持った「引き算」にあります。スコアを下げていた Title(敬称)を一度捨て、モデルをスリム化した上で、全く新しい切り口である Embarked を追加しました。

  • 多重共線性の解消: 性別・年齢・敬称という似通った情報の衝突を解消し、モデルの迷いを取り除きました。
  • 乗船港が示す「背景」: シェルブール(C)=富裕層、サウサンプトン(S)=一般層といった、港ごとの生存傾向が、Pclassだけでは説明しきれなかった微細な生存確率を補完しました。

2. 【実装】0.78468 を叩き出した最終コード

シンプルながらも強力な、現時点での「最適解」と言えるコード全文です。Embarkedの欠損値を最頻値で埋め、ダミー変数化して投入しています。

import pandas as pd
import numpy as np
from sklearn.ensemble import RandomForestClassifier

# 1. データの読み込み
train_data = pd.read_csv('train.csv')
test_data = pd.read_csv('test.csv')

# 2. Embarked(乗船港)の欠損値補完
# 最も多い乗船港である 'S' で補完
train_data['Embarked'] = train_data['Embarked'].fillna('S')
test_data['Embarked'] = test_data['Embarked'].fillna('S')

# 3. 安定した前処理の再現(属性別Age補完 & 家族サイズ)
group_cols = ['Pclass', 'Sex']
train_data['Age'] = train_data['Age'].fillna(train_data.groupby(group_cols)['Age'].transform('median'))
test_data['Age'] = test_data['Age'].fillna(test_data.groupby(group_cols)['Age'].transform('median'))

for df in [train_data, test_data]:
    df['FamilySize'] = df['SibSp'] + df['Parch'] + 1

# テストデータの運賃欠損を中央値で補完
test_data['Fare'] = test_data['Fare'].fillna(test_data['Fare'].median())

# 4. 学習に使用する特徴量の定義
# 迷走した Title はあえて外し、Embarked を新規採用
features = ["Pclass", "Sex", "Age", "SibSp", "Parch", "Fare", "FamilySize", "Embarked"]

# 5. カテゴリ変数をダミー変数に変換
X = pd.get_dummies(train_data[features])
y = train_data["Survived"]
X_test = pd.get_dummies(test_data[features])

# 学習とテストの列を一致させる
X, X_test = X.align(X_test, join='left', axis=1, fill_value=0)

# 6. モデル学習(500本の決定木、最大深さ5)
model = RandomForestClassifier(n_estimators=500, max_depth=5, random_state=1)
model.fit(X, y)

# 7. 予測の実行と提出用CSV作成
predictions = model.predict(X_test)
output = pd.DataFrame({'PassengerId': test_data.PassengerId, 'Survived': predictions})
output.to_csv('submission_final_best.csv', index=False)

print("Score 0.78468 達成の予測ファイルを保存しました。")

3. 実験結果:0.77751 → 0.78468 へ跳ねる!

特徴量を1つ入れ替え、整理しただけで、スコアは劇的に改善しました。

  • 前回(Title追加): Score 0.77751
  • 今回(Title削除+Embarked追加): Score 0.78468 (New Record!)

4. 考察:エンジニアリングの本質は「整理整頓」にあり

エンジニア的な視点:
今回の結果が教えてくれたのは、「良いデータ」を足すことと同じくらい、「不要な相関を削る」ことが重要であるという事実です。一時は 0.77 台まで落ち込み絶望しましたが、そこで立ち止まらずに「なぜ落ちたのか?」を考え、別の軸(Embarked)に切り替えたことが勝機となりました。0.785の壁も見えてきました。次はこの安定した土台の上に、さらなるエッセンスを加えていきます。


自己ベスト更新の余韻に浸りつつも、Kaggleの道はまだ続きます。今回の勝利で「情報の質と整理」の重要性が証明されました。次は、今回あえて削った `Title` を「ノイズにならない形」で再統合するか、あるいは `Cabin`(客室)の深淵に踏み込むか……。戦略を練り直します!

PR