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

【Kaggle挑戦記】Titanic 攻略 #11:血縁データの統合。「家族サイズ」が0.78の壁を打ち破る

前回(攻略 #10)のデバッグでは、自作の「子供フラグ」がモデルにとって不純なノイズとなっていた現実を直視しました。今回はその反省を活かし、バラバラに存在していた「血縁データ」をロジカルに統合。ついに 0.78 の壁を突破する強力なヒント FamilySize(家族人数) を導入します。

1. 今回の着眼点:孤立か、連帯か

タイタニックのデータには、家族に関する項目が2つ用意されています。しかし、これらを別々に見ていては「その人がどれほどの集団で行動していたか」という実態が見えてきません。

  • SibSp: 兄弟、配偶者の数
  • Parch: 両親、子供の数

避難の際、1人で行動していたのか、あるいは守るべき家族がいたのか。この「群れ」の大きさを一つの指標として統合し、モデルに新たな視点を与えます。自分自身(+1)を足すことで、「1 = 単独客」「2以上 = 家族連れ」という、生存率を分ける明確な境界線が生まれます。

2. 【実装】FamilySize導入とモデル構築の全コード

属性別Age補完を継承しつつ、FamilySizeを計算してランダムフォレストに投入するまでの全工程です。

import pandas as pd
from sklearn.ensemble import RandomForestClassifier

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

# 2. Age(年齢)を Pclass×Sex の中央値で補完
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'))

# 3. 家族サイズ(FamilySize)の算出
train_data['FamilySize'] = train_data['SibSp'] + train_data['Parch'] + 1
test_data['FamilySize'] = test_data['SibSp'] + test_data['Parch'] + 1

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

# 4. 学習に使用する特徴量の定義
features = ["Pclass", "Sex", "Age", "SibSp", "Parch", "Fare", "FamilySize"]

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

# 5. モデルの構築と学習(木500本、深さ5)
model = RandomForestClassifier(n_estimators=500, max_depth=5, random_state=1)
model.fit(X, y)

# 6. 予測と提出ファイルの出力
predictions = model.predict(X_test)
output = pd.DataFrame({'PassengerId': test_data.PassengerId, 'Survived': predictions})
output.to_csv('submission_family_size.csv', index=False)

print("Score 0.78229 達成用の提出ファイルを保存しました。")

3. 実験結果:0.77990 → 0.78229 へ上昇!

家族サイズを導入した結果、ついに停滞していたスコアが大きく動きました。

  • 前回(Age補完のみ): Score 0.77990
  • 今回(FamilySize追加): Score 0.78229

エンジニア的な考察:
ついに 0.78 の大台に乗りました。単なる数値だった「SibSp」と「Parch」を合計して『家族というひとつの単位』として捉え直したことで、モデルは「独身男性(死亡率高)」や「小家族(生存率高)」という構造を、より正確に切り分けられるようになったと言えます。アルゴリズムをいじるのではなく、データの「見方」を変えることが勝利の鍵であることを証明しました。

4. 次なる一手:名前の「敬称」から社会的地位を暴く

0.78229 というスコアは一つの通過点に過ぎません。まだ伸び代は十分にあります。次は、これまで手をつけていなかった巨大な情報源 Name(名前) の解析に挑みます。ここから「Mr.」「Miss.」「Master.」といった敬称を抜き出せば、年齢だけでは判別できない「既婚・未婚」や「家柄(社会的地位)」という決定的なヒントが手に入るはずです。


「質の高い燃料(特徴量)」を投入することで、ランダムフォレストは見違えるような精度を見せ始めました。この勢いのまま、次はテキストデータの解析に踏み込み、さらなる高みを目指します。


PR