【Kaggle】タイタニックの分析をやってみる

Kaggleに登録してみたので備忘録を。
初心者ということもあり、まずは王道のタイタニックデータを使った分析をしてみた。

データの前処理


データはKaggle内にあり、TrainとTestにあらかじめ分けられている。
生存有無を予測する2値分類問題であり有名なデータ。

import numpy as np
import pandas as pd
from scipy import stats
 
#-- import
train = pd.read_csv("../input/titanic/train.csv")
test = pd.read_csv("../input/titanic/test.csv")


このデータは欠損があるようなので、今回は諸先輩方のブログを参考に中央値と最頻値で補完する。 また、カテゴリ変数は数値化しておく。

###--- 欠損処理
train["Age"] = train["Age"].fillna(train["Age"].median()) #--中央値で補完
train["Embarked"] = train["Embarked"].fillna("S") #-- 最頻値で補完 train["Embarked"].mode()

test["Age"] = test["Age"].fillna(test["Age"].median()) #--中央値で補完
test["Fare"] = test["Fare"].fillna(test["Fare"].median()) #--中央値で補完
 
###--- カテゴリの数値化
train["Sex"] = train["Sex"].map({'male':0, 'female':1})
train["Embarked"] = train["Embarked"].map({'S':0, 'C':1, 'Q':2})

test["Sex"] = test["Sex"].map({'male':0, 'female':1})
test["Embarked"] = test["Embarked"].map({'S':0, 'C':1, 'Q':2})


※あとから気づいたが、Embarked はダミー変数化した方が良かった。
pd.get_dummies(train, columns=['Embarked'])

バリデーションデータの準備


Kaggleでは、テストデータ(正解ラベルなし)があらかじめ準備されているため、次の手順で分析してみる。
* 訓練データを訓練&検証データに分割
* F1-スコアでモデル評価
* ベストモデルを用いてテストデータで予測

from sklearn import model_selection

Xval = ["Pclass", "Sex", "Age", "Fare", "Embarked"]

df_y = train["Survived"].values
df_X = train[Xval].values

train_X, valid_X, train_y, valid_y = model_selection.train_test_split(df_X, df_y, random_state=19)

test_X = test[Xval].values


モデル作成


初めてなので色々なモデルを試してみた(グリッドサーチ、ランダムサーチなどはしていない)。
順番に決定木、ランダムフォレスト、ロジスティック回帰(L2正則化、L1正則化、両方0.5ずつ)、線形サポートベクターマシーン(L2正則化、L1正則化)、サポートベクターマシーン(カーネル:Linear、rbf、poly、sigmoid)。

from sklearn.tree import DecisionTreeClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import LinearSVC, SVC
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report, confusion_matrix, f1_score
 
modfnc = [DecisionTreeClassifier(random_state=19)
          ,RandomForestClassifier(random_state=19)
          ,LogisticRegression(random_state=19, penalty="l2")
          ,LogisticRegression(random_state=19, penalty="l1", solver='liblinear')
          ,LogisticRegression(random_state=19, penalty="elasticnet", solver='saga', l1_ratio=0.5)
          ,LinearSVC(random_state=19)
          ,LinearSVC(random_state=19, penalty='l1', loss='squared_hinge', dual=False)
          ,SVC(kernel='linear', random_state=19)
          ,SVC(kernel='rbf', random_state=19)
          ,SVC(kernel='poly', random_state=19)
          ,SVC(kernel='sigmoid', random_state=19)
         ]
 
score=0
 
for modfnc1 in modfnc:
    model = modfnc1
    model.fit(train_X, train_y)
    pred_y = model.predict(valid_X)
    print("----",modfnc1,"-----")
    #print(model.score(valid_X, valid_y))
    print(f1_score(valid_y, pred_y, average="micro"))
    #print(confusion_matrix(valid_y, pred_y))
    #print(classification_report(valid_y, pred_y))
    #print()
    
    if score < f1_score(valid_y, pred_y, average="micro"):
        best_model = modfnc1
        score = f1_score(valid_y, pred_y, average="micro")
 
print("---- best model ----")
print(best_model)
print(score)


このうち、F1-スコアでの評価ではランダムフォレストが最も良好だった。

---- DecisionTreeClassifier(random_state=19) -----
0.7713004484304933
---- RandomForestClassifier(random_state=19) -----
0.8430493273542601
---- LogisticRegression(random_state=19) -----
0.8071748878923767
---- LogisticRegression(penalty='l1', random_state=19, solver='liblinear') -----
0.8251121076233184
---- LogisticRegression(l1_ratio=0.5, penalty='elasticnet', random_state=19,
                   solver='saga') -----
0.6905829596412556
---- LinearSVC(random_state=19) -----
0.7309417040358744
---- LinearSVC(dual=False, penalty='l1', random_state=19) -----
0.8251121076233184
---- SVC(kernel='linear', random_state=19) -----
0.8116591928251121
---- SVC(random_state=19) -----
0.6636771300448431
---- SVC(kernel='poly', random_state=19) -----
0.6278026905829597
---- SVC(kernel='sigmoid', random_state=19) -----
0.5919282511210763
 
---- best model ----
RandomForestClassifier(random_state=19)
0.8430493273542601


テストデータで予測


ベストモデル(ランダムフォレスト)を使ってテストデータで予測を行う。
Kaggleのテストデータには正解ラベルが入っておらず、予測結果をKaggleの指定ページに提出してスコアを出す仕組みである(カンニングできない)。

best_model.fit(train_X, train_y)
pred_y2 = best_model.predict(test_X)
 
submission = pd.DataFrame({'PassengerId':test['PassengerId'], 'Survived':pred_y2})
submission.to_csv('submission.csv', index = False)


実際に結果を提出してみたところ、Score : 0.75119(44,476位)だった。

ハイパーパラメータを何もいじらずだったので、次はグリッドサーチやランダムサーチを使ってベストモデルを探してみたい。
もしくはポピュラーな LightGBMXGboost の実装をしてみたい(こっちの興味の方が強い)。

参考


【Kaggle超初心者向け】Titanicにチャレンジしてみた - Qiita
Kaggleコンペの提出データをKernelから提出する - Qiita
機械学習初心者がKaggleのTitanic課題でモデルを作る | 4番は司令塔

当ブログの関連記事:
【統計】ロジスティック回帰分析 - こちにぃるの日記
【機械学習_Python】Ridge回帰、Lasso回帰、Elastic Net回帰 - こちにぃるの日記
【機械学習_Python】決定木とランダムフォレスト - こちにぃるの日記
【機械学習_Python】サポートベクターマシーン - こちにぃるの日記

本ブログは個人メモです。 本ブログの内容によって生じた損害等の一切の責任を負いかねますのでご了承ください。