LoginSignup
10
7

More than 5 years have passed since last update.

kaggleのタイタニックコンペで0.808

Last updated at Posted at 2019-04-24

kaggleのタイタニックコンペで0.808

1.はじめに

 本格的にデータサイエンスの勉強を初めて1ヶ月経ったので、以前挑戦してちんぷんかんぷんだったタイタニックのコンペに再び取り組むことにした。0.8が一つの目安らしいので、それを超えるのを目標とする。タイタニックのコンペとは、タイタニックの沈没の際に乗っていた乗客の生死を予測するコンペのことで、初心者向けらしい。

2. 特徴量エンジニアリング

 まずは基本的なライブラリのインポートとデータの読み込み。


import pandas as pd
import numpy as np
import seaborn as sns

train = pd.read_csv("train.csv")
test = pd.read_csv("test.csv")
gender_submission = pd.read_csv("gender_submission.csv")

データの状態などを確認。


train.head()
train.info()
train.describe()
train.isnull().sum()
test.head()
test.info()
test.describe()
test.isnull().sum()

結果を見てみると、trainにはAge,Cabin,Embarkedにデータの欠損があり、testにはAge,Fare,Cabinにデータの欠損がある。特にAgeとCabinは欠損値が多すぎるので、最終的には特徴量から外すかも。

次に相関などについてみていく。


train_corr = train.corr()
sns.heatmap(train_corr)

  heatmap.png

PclassとFareはSurvivedと関係が深そうなので、そこをみていく。
また、タイタニックの事故の際には女性を優先的に助けたそうなので、Sexも重要そうだ。

sns.countplot("Sex",data=train,hue="Survived")

countplot_sex.png

male,femaleの順に並んでいる。やはり女性を優先的に助けていたようだ。生き残った男性と亡くなった女性が気になるので、そこを調べる。

sns.factorplot(x="Pclass",y="Age",data=train,kind="violin",hue="Sex",col="Survived")

violin.png

男性は若いほど生き残りやすいことがわかる。しかし、女性についてはよくわからない。


train_died_female = train[train["Survived"]==0]
sns.countplot("Pclass",data=train_died_female)

died_female.png

女性で亡くなっているのは、ほとんどPclassが3の人であったようだ。
ここまでのまとめとして、Age,Pclass,SexはSurvivedとかなり関連がある。
しかしAgeには欠損値が多すぎるため、何か方法を考えなければならない。これはカーネルから得た方法だが、Nameを利用する。Nameについて。1行目は、Braund, Mr. Owen Harris
さんだ。この人はMrであるから男性である。同様にみていくと、Mrs,Miss,Master等がある。これを利用すれば、Ageの欠損値問題は解決でき、性別もわかるためSexも特徴量から外すことができる。


for dataset in [train,test]:
    dataset["title"] = dataset["Name"].str.split(",",expand=True)[1].str.split(".",expand=True)[0]

少し問題がある。


train["title"].value_counts()
test["title"].value_counts()

Mr 517
Miss 182
Mrs 125
Master 40
Dr 7
Rev 6
Major 2
Mlle 2
Col 2
Mme 1
Lady 1
Ms 1
Capt 1
the Countess 1
Jonkheer 1
Sir 1
Don 1
Name: title, dtype: int64

Mr 240
Miss 78
Mrs 72
Master 21
Rev 2
Col 2
Ms 1
Dona 1
Dr 1
Name: title, dtype: int64

よくわからない名称がたくさん出てきた。
しょうがないので、少数の名称はすべてexeptionにしてしまう。

for miner_title in [" Dr"," Rev"," Mlle"," Major"," Col"," Ms"," Lady"," Mme"," Capt"," Jonkheer"," the Countess"," Sir"," Don"]:
    train["title"] = train["title"].replace(miner_title,"exeption")
for miner_title in [" Dr"," Rev"," Col"," Ms"," Dona"]:
    test["title"] = test["title"].replace(miner_title,"exeption")

一応titleについてみてみる。

sns.factorplot("title",data=train,hue="Survived",kind="count")

title.png

かなりわかりやすくなった。Mrは死者が多いが、Pclassが1のMrは比較的に助かった人も多い。女性でPclassが1か2であればほぼ死ぬことはなく、Pclassが3であると半々で助かる。特徴がよく現れているので、これは特徴量として使うこととする。

sns.jointplot(x="Fare",y="Age",data=train)

train_fare_age.png

やたらFareの高いひとが3人いた。外れ値なので削除。

train[train["Fare"]>=400]
train = train.drop([258,679,737],axis=0)

testにはEmbarkedの欠損がないため、trainのEmbarkedの欠損値を含むデータを削除。

train[train["Embarked"].isnull()]
train = train.drop([61,829],axis=0)
trainX = train.drop(["Age","Name","Sex","Ticket","Cabin"],axis=1)
testX = test.drop(["Age","Name","Sex","Ticket","Cabin"],axis=1)

すでに使わないことにしたカラムを削除。

test[test["Fare"].isnull()]
testX["Fare"] = testX["Fare"].fillna(round(testX[testX["Pclass"]==3][testX["title"]==" Mr"]["Fare"].mean(),4))

testのFareに一つ欠損があったが、Pclassとtitleが同じ人の平均で補う。

sns.factorplot("SibSp",data=trainX,hue="Survived",kind="count")
sns.factorplot("Parch",data=trainX,hue="Survived",kind="count")
sns.factorplot("Embarked",data=trainX,hue="Survived",kind="count")

SibSp,Parch,Embarkedについてみたが、どれも特徴がでているため使うことにする。

trainX_dum = pd.get_dummies(trainX)
testX_dum = pd.get_dummies(testX)
trainX_dum = trainX_dum.drop(["Embarked_S","title_exeption"],axis=1)
testX_dum = testX_dum.drop(["Embarked_S","title_exeption"],axis=1)

データのダミー変数化とダブりの削除。

from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
trainX_dum_std = trainX_dum
testX_dum_std = testX_dum
trainX_dum_std[["Fare","Pclass"]] = ss.fit_transform(trainX_dum[["Fare","Pclass"]])
testX_dum_std[["Fare","Pclass"]] = ss.transform(testX_dum[["Fare","Pclass"]])
trainY = trainX_dum["Survived"]
trainX_dum = trainX_dum.drop("Survived",axis=1)

特徴量をスケーリングし、目的関数を準備。

3. モデリング

ロジスティック回帰や決定木、ランダムフォレストなど、いろいろ試したがサポートベクターマシンのスコアが最もよかったのでそれを載せておく。

from sklearn.model_selection import GridSearchCV
from sklearn.svm import SVC

param_grid = {'C': [0.001, 0.01, 0.1, 1, 10, 100],  'gamma' : [0.001, 0.01, 0.1, 1, 10, 100]}


X_train, X_test, y_train, y_test = train_test_split(trainX_dum_std, trainY, random_state=0)

grid_search = GridSearchCV(SVC(), param_grid, cv=5)

grid_search.fit(X_train, y_train)

グリッドサーチをして、
これを提出したところ、0.794だった。このときのパラメータは、C:100,gamma:0.01。
ここからは手作業だが、C:250,gamma:0.01 で0.8086をとれた。

4. 結果

 目標を達成することはできた。しかし、カーネルをみているとLightGBMなどのアンサンブル系を使っている人が多く、まだスコアを伸ばす余地はあると思う。SibSpとParchを合わせてfamily_sizeを作ることもできるようだが、今回はしていない。

5. 参考文献

 主にこのカーネルを参考にした。
 https://www.kaggle.com/ldfreeman3/a-data-science-framework-to-achieve-99-accuracy

10
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
7