KaggleのTitanicのチュートリアルをランダムフォレストで解く

(2018-05-29)

ランダムフォレストはデータや特徴量をランダムにサンプリングして決定木を複数生成し並列に学習するアンサンブル学習のBaggingという種類の手法。 決定木なので特徴量の影響が分かりやすく、単一の決定木と比べて過学習を防ぐことができる。

KaggleのTitanicのチュートリアルをXGBoostで解く - sambaiz-net

train.csvtest.csvをKaggleからダウンロードする。 csvにはタイタニックの乗客者リストが含まれ、test.csvには生還したかを表すSurvivedが抜けている。 これを予測するのがこのコンペティションの目的だ。

データのうちFareやAge、Embarkedは入っていないものがあって、これらの欠損値をどう扱うという問題がある。

df = pd.read_csv('./train.csv')
print(len(df))
print(df.isnull().sum())
891
PassengerId      0
Survived         0
Pclass           0
Name             0
Sex              0
Age            177
SibSp            0
Parch            0
Ticket           0
Fare             0
Cabin          687
Embarked         2
dtype: int64

連続値をとるFareとAgeは平均を取り、Embarkedは欠損値用の値にしてみた。数値化できないものについては除いている。

def preprocess(df):
    df['Fare'] = df['Fare'].fillna(df['Fare'].mean())
    df['Age'] = df['Age'].fillna(df['Age'].mean())
    df['Embarked'] = df['Embarked'].fillna('Unknown')
    df['Sex'] = df['Sex'].apply(lambda x: 1 if x == 'male' else 0)
    df['Embarked'] = df['Embarked'].map( {'S': 0, 'C': 1, 'Q': 2, 'Unknown': 3} ).astype(int)
    df = df.drop(['Cabin','Name','PassengerId','Ticket'],axis=1)
    return df

scikit-learnののRandomForestClassifierで学習させる。 デフォルトの木の数は10で、特徴量の数はsqrt(n_features)となっている。 feature_importances_で各特徴量の重要度を出すことかできる。

from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.ensemble import RandomForestClassifier
import numpy as np
import csv

def train(df):
    train_x = df.drop('Survived', axis=1)
    train_y = df.Survived
    (train_x, test_x ,train_y, test_y) = train_test_split(train_x, train_y, test_size = 0.33, random_state = 42)

    clf = RandomForestClassifier(random_state=0)
    clf = clf.fit(train_x, train_y)
    pred = clf.predict(test_x)
    print(accuracy_score(pred, test_y))
    
    features = train_x.columns
    importances = clf.feature_importances_
    indices = np.argsort(importances)
    for i in indices[::-1]:
        print("{:<15} {:f}".format(features[i], importances[i]))
    return clf

import pandas as pd
df = pd.read_csv('./train.csv')
df = preprocess(df)
clf = train(df)

精度は8割ほどで、AgeとFareの影響が大きいようだ。

0.803389830508
Age             0.267060
Fare            0.262733
Sex             0.224451
Pclass          0.097958
SibSp           0.058860
Parch           0.048173
Embarked        0.040765

このモデルで予測したSurvivedのcsvを出力してKaggleにアップロードするとスコアと順位が出る。

df_test_origin = pd.read_csv('./test.csv')
df_test = preprocess(df_test_origin)
submit_data =  pd.Series(clf.predict(df_test), name='Survived', index=df_test_origin['PassengerId'])
submit_data.to_csv('submit.csv', header=True)

スコアと順位

参考

機械学習の実践入門ーRandom Forestの要約 | GMOアドパートナーズグループ TECH BLOG byGMO

【Pythonで決定木 & Random Forest】タイタニックの生存者データを分析してみた - これで無理なら諦めて!世界一やさしいデータ分析教室