タイタニック号の乗客の生存予測〜80%以上の予測精度を超える方法(探索的データ解析編)

タイタニック号の乗客の生存予測〜80%以上の予測精度を超える方法(探索的データ解析編)

今さらですが、ついにKaggleのタイタニック チュートリアル(titanic tutorial)でAccuracy 80%を達成できました。
※過去に3つほどtitanic tutorialについての記事を書いています。titanic tutorialって何?っていう方は以下に詳しくまとめていますのでご参照ください。

今回から2~3回にわたって、どうやってAccuracy 80%を超えられたのかを備忘録的にまとめようと思います。
まず、予測モデルの構築に必要な特徴量を見極めるために、改めて探索的データ解析(EDA)を実施します。
※EDAの目的はきれいなグラフを作って満足することではなく、モデル構築に必要なデータを見極めていくことです。
解析に使用する言語はPythonでバージョンは3.7です。
今回のEDAでは各説明変数ごとに次の分析していきます。

  • Survived(生存)と説明変数の関係
    予測モデル構築時に使用する特徴量を選定するため
  • 学習データとテストデータの分布
    予測モデルの訓練に使うデータと予測に使うデータの分布に偏りがないかを事前に把握するため

データ準備

ライブラリ

まず前提として以下のライブラリをimportします。
今回のEDAでは使わないライブラリが多数含まれています。今後の予測モデル構築で使うライブラリもimportしています。
input:

データ読込と加工

学習データとテストデータを読み込みます。
データはKaggleの以下のページからダウンロードできます。


input:

output:

次に学習データとテストデータの分布を調べるために、データをマージします。
マージする前に学習データとテストデータに以下の処理をします。

  • 学習データとテストデータを区別できるようにWhatIsDataカラムを追加
  • テストデータにSurvivedカラムを追加

input:

探索的データ解析

データの準備が終わったので、ここからは各説明変数ごとにデータをみていきます。
ですが、その前に各説明変数とSurvived(生存)の関係を調べる上でベースラインとなる学習データ全体における生存率を確認しておきます。
input:

output:

生きるか死ぬかの2パターンだから生存率は0.5と機械的に考えてしまいがちですが、学習データにおける生存率は約0.38です。
これから各説明変数と生存率の関係をみていくとき、この生存率0.38という数値が判断基準になります。

Pclass

PclassごとのSurvivedの平均(生存率)を算出します。
input:

output:

ベースライン生存率が0.38だったので、Pclassと生存率には何らかの関係がありそうです。
Pclassごとの乗客数もみてみます。


グラフからPclassが3の乗客に死亡者(Survived:0)が多いことがわかります。
次に学習データとテストデータの分布を確認します。
input:

output:

学習データとテストデータ間のPclassの乗客数の分布に大きな偏りはなさそうです。

Name

Name(乗客の名前)はSurvived(生存)とは関係がなさそうですが、いったん実データを眺めてみます。
input:

output:

Nameには文字通り乗客の名前が格納されています。
名前を眺めていると、真ん中に共通している部分があることがわかります。
英語表記の名前はfirst name, middle name, last nameで表現されていて、このmiddle nameの部分になんらかの情報が含まれていそうです。
いったんこのmiddle nameの部分を切り出してみます。
(middle nameはhonorific(敬称)と呼ばれるので、コードではhonorificと表記しています。)
input:

output:

Miss, Mrs, Masterが多くの乗客で共通しています。
次に学習データとテストデータの分布を確認します。
input:

output:

上記の結果を眺めてみると、テストデータにはなく学習データにしかないmiddle name(honorific)がちらほらと存在しています。
このようなデータは予測モデル構築の際には邪魔なデータになるので学習データから除外します。
その上で生存率を確認してみます。
例えば、学習データにしか存在しないCaptは、おそらく船長を表しているはずです。
船長は予想通り死亡しています。
テストデータに存在していないこのデータを学習データにいれることは、少なくともモデルをよくする方に働かないと考えます。

input:

output:

ベースライン生存率0.38と比較すると、敬称(honorific)は生存と関係がありそうです。
Col, Dr, Mlle, Ms, Revのレコード数がわずかしかないため、統合します。
input:

output:

やはり敬称(honorific)は生存と関係がありそうです。

Fare

まずはFare(運賃)をSurvivedに分けて分布を確認します。
input:

output:

全体で見たときにFareが少ない乗客が大半で、かなり右に裾野が広がっていることがわかります。
Fareのskewness(歪度)を確認します。
input:

output:

skewnessが大きい値となっていて分布が歪んでいるので、対数変換をして分布を修正します。
input:

output:

グラフをみると、少なくとも死亡者(Survived:0)に関してはSurvivedと関係がありそうです。

Age

Ageはそもそも欠損が多い変数です。
いたって素朴な想像ですが、年齢の欠損ってそもそも生存率に関係があるのでは?と思ったので、いったん欠損有無による生存率をみてみます。
Ageが欠損しているってことは死亡しているからそもそもデータが取れていないんじゃ?と思ったためです。
input:

output:

う〜ん、これだと生存率に差があるかどうかはなかなか言いにくいかもしれません。
いったん欠損値を除外して分布をみてみます。
input:

output:

グラフを見ると、20歳以降の分布は生存、死亡ともに似通っていますが、0~20歳までの分布に差があります。
子供は生き残りやすかったと言えそうです。

FamilySize

与えられたデータには存在しない、FamilySize(家族数)とう変数を追加して分布を確認します。
input:

output:

グラフを見ると、家族数:1(単身)は生存率が低く、家族数:2~4(小家族)は生存率が高く、それ以降はまた生存率が低いことがわかります。
FamilySizeと生存の間に線形関係がなさそうなのでビニング処理をします。
input:

output:

ビニング処理のFamilySizeは生存と関係がありそうです。
小さい家族は生存しやすく、大家族は生存しにくかったと言えます。

Cabin

Cabin(客室)を見ていきます。
この変数に関しては以前このブログでも考察をあげていますので詳しくは以下をご参照ください。


Cabinの頭文字は部屋がどの階層にあったのかを示すものなので、まずはCabinの頭文字ごとの生存率を確認します。
input:

output:

Cabinの頭文字は生存率と何らかの関係がありそうです。
次に学習データとテストデータの分布を確認します。
input:

output:

Cabin:Tに関しては学習データにしか存在しないため、Tは予測モデル構築時には学習データから除外する方がよさそうです。

Ticket

最後にTicketを調べていきます。
まずはTicketにはどんなデータが入っているのかを確認します。
input:

output:

Nameと違って規則性を見つけるのは難しそうです。先頭が英語あるいは数字の場合があるので、いったんTicketの1文字目に着目してデータをまとめてみます。
input:

output:

上記のデータをみてみると、Ticketの1文字目と生存には何らかの関係がありそうです。
学習データとテストデータ間の分布をみてみます。
input:

output:

学習データにしか存在していない項目がちらほらあります。
ただ、Ticketについては先頭の1文字目がどう言う意味を表すのかがよくわからないため、いったん予測モデルでの使用は避けます。
意味がわかる特徴量のみを使用して予測モデルを構築したいためです。

次回からは今回のEDAでSurvivedに関係がありそうな特徴量を使った予測モデルの構築からKaggleへの予測結果の提出までを説明します。