タイタニック生存問題をやってみた【Kagglerになる#1】

#Kaggleにチャレンジします
データサイエンティストといえばKaggle、ということで色々チャレンジしていきます。
まず最初は下記のタイタニック生存問題から取り組みます。
▼タイタニック生存問題
https://www.kaggle.com/c/titanic
#参考
初心者のため、色んなkernalや基本書の寄せ集めです。
コードも整理されていませんがご了承ください。
▼参考にしたkernel
https://www.kaggle.com/startupsci/titanic-data-science-solutions
英語ですが分かりやすく書いてくださっているのでオススメです。

#実行環境
- Python 3.6
- Jupyter notebook
諸々のライブラリはAnacondaで入れています。

#Kaggleチャレンジ
##データの確認
まずデータの中身を確認していきます。
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395230/d22f8652-ac26-fcc2-9519-0f62a8fa4fb1.png)
データの列が12行あります。各項目の意味は下記とのことです。

| 項目       |       意味 |   
|:-----------------|:------------------|
|PassengerID | 乗客ID |
| Survived| 生存したか否か(1:生存,2:死亡) |
| Pclass  |チケットのクラス（1 = 1st, 2 = 2nd, 3 = 3rd）| 
| Name  | 乗客の名前 | 
| Sex| 乗客の性別 | 
|Age | 乗客の年齢 | 
|SibSp | 兄弟や配偶者の数 | 
|Parch | 両親や子供の数 | 
|Embarked  | どの港から乗船したか(C = Cherbourg, Q = Queenstown, S = Southampton) | 
|ticket | チケット番号 | 
|Parch | 部屋番号 | 

何となく、生存に関係してそうな変数と全く関係しなそうな変数が存在しますね。
乗客IDや名前、チケット番号は全く関係なさそうです。
逆に性別や年齢とかは強く関係してそうですね。（タイタニックの映画を見てた時、何となく女性・子どもから順に救命ボートに乗っていたような。。）
その辺りも含めて以下で見ていきます。
###データを見る
####データを読み込む

```Python
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline

train = pd.read_csv('train.csv')
test = pd.read_csv('test.csv')
combine = [train,test]
```
####基本統計量を確認する
```Python
train.describe()
```
このような感じで表示されます。
.describe()で表示されるのは、データが数値として入っているもののみです。

![図2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395230/b7e003fc-d531-7b07-c82d-1f845f94ed78.png)

何となく特徴的なのはこのあたりでしょうか。

- 年齢は0歳から80歳まで
- 料金は最大512＄払っている人がいる、結構バラつきが多いっぽい
- 兄弟と配偶者が合わせて8人乗っている人がいる

####null値を確認する
```Python
train.isnull().sum()
```
![図7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395230/4d0a62ec-67c4-2af5-7698-b222e250032b.png)

```Python
test.isnull().sum()
```

![図9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395230/763a1bf6-1af5-6a38-b69a-fbb1365c6189.png)

Cabinにはnull値が多いので、落としてしまって大丈夫そうです。
AgeとEmbarkedとFareは何らか補完しようと思います。


とりあえず各項目と、生存・死亡の関係を可視化してみます。

###各項目と生存・志望の関係を可視化する
####チケットクラスとの関係
```Python
train[['Pclass','Survived']].groupby('Pclass', as_index = False).mean().sort_values(by = 'Survived' ,ascending = False)

```
![図3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395230/2719e446-62ec-7666-efde-77b0cfd2e0fc.png)

どうもクラスの高い人ほど生存しているようです。。
クラスの高い人から救命ボートに乗せてもらえた感じなんでしょうか。
####乗船場所との関係
```Python
train[['Embarked','Survived']].groupby('Embarked', as_index = False).mean().sort_values(by = 'Survived', ascending = False)

```
![図4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395230/7538eaed-6387-e969-0f32-86c7dd642df3.png)

Cherbourgから乗船した人の生存率が高かったようです。
乗船した場所によって、客室の位置が違ったたのか、客層が違ったのか。。

####性別との関係

```Python
train[['Sex','Survived']].groupby('Sex', as_index = False).mean().sort_values(by = 'Survived', ascending = False)

```

![図5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395230/b433c517-8fbf-522e-5072-c4acba8d9edd.png)

女性の方が圧倒的に生存していますね。。
女性が優先的に救助されたようです。

####年齢との関係

```Python
g = sns.FacetGrid(train , col = 'Survived')
g.map(plt.hist,"Age",bins = 20)
```

![図6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395230/81bb0208-a93d-28bb-74da-a2fe9e8a7456.png)

子供の生存率が高く、20～40歳の成長率が低く見えます。
やはり、女性・子供から優先的に救助されたようですね。

何となく主要な項目との関係性が見えてきたところで、
データを整理しています。

###データを整理する
####関係のなさそうな項目を落とす

```Python
train = train.drop(['PassengerId','Ticket','Cabin','Name'],axis = 1)
test = test.drop(['PassengerId','Ticket','Cabin','Name'],axis = 1)
combine = [train,test]
train.head()
```
![図8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395230/76dad4f3-a039-e57b-d8ab-3467d9f5d6e9.png)

予測に関係なさそうな「PassengerId」「Ticket」「Name」と、
null値が多く含まれている「Cabin」を落としました。

####null値を補完する

```Python
freq_port = train.Embarked.mode()[0]
for dataset in combine:
    dataset['Embarked'] = dataset['Embarked'].fillna(freq_port)
train['Age'] = train['Age'].fillna(train['Age'].mean())
test['Age'] = test['Age'].fillna(test['Age'].mean())
test['Fare'] = test['Fare'].fillna(test['Fare'].mean())
```

Embarkedについては最頻値で、その他は平均値で補完します。

####文字を数値に変換する

```Python
#femaleを0に、maleを1に変換
#Sを0に、Cを1に、Qを2に変換
for dataset in combine:
    dataset['Sex'] = dataset['Sex'].replace('female',0).replace('male',1)
    dataset["Embarked"] = dataset["Embarked"].map({'S':0,'C':1,'Q':2}).astype(int)
train.head()
```
文字で記載されていた、「Sex」と「Embarked」の中を数値を変換します。
これで下準備は完了です。

##予測する
###決定木分析とパラメーターのチューニング

```Python
y = train.iloc[:,:1]
X = train.iloc[:,1:]

from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier as DTC
from sklearn.model_selection import GridSearchCV

X_train_val,X_test,y_train_val,y_test = train_test_split(X,y,random_state = 1)
estimator = DTC(random_state = 0)

param_grid = [{'max_depth':[3,5,10,20,50],'min_samples_split':[3,5,10,20,50]}]
cv = 5

tuned_model.fit(X_train_val,y_train_val)
pd.DataFrame(tuned_model.cv_results_).T
```
今回は、決定木モデルを使用してタイタニック問題を解きます。
上記コードでは、決定木のハイパーパラメーターである"max_depth"と"min_sample_split"
をGridSearchを用いて最適化を試みています。

![図10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395230/e54582cd-9460-efd4-b876-a9a39fe1e706.png)

結果はこんな感じです。一杯で出てきますね。
全て見ていられないので、最適なパラメーターをmodelに引き継ぐコードを実行します。

```Python
tuned_model.best_params_
model = tuned_model.best_estimator_
```
今回だと、下記が最適だったようです。
{'max_depth': 3, 'min_samples_split': 3}

###予測と提出用ファイル作成

```Python
pred = model.predict(test)
test2 = pd.read_csv('test.csv')
submit = pd.DataFrame({'PassengerId':test2['PassengerId'],'Survived':pred})
submit.to_csv("gender_submission.csv",index=False)
```
こちらで、提出用ファイルの作成が完了です。
それでは投稿していきます。

##投稿結果の確認

![図11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395230/d294b0c0-b235-344d-9eed-8580f163709e.png)

accuracyでスコア0.79425となりました。
ランキングでは2077/11237(2019年4月24日現在)となっています。
ほぼ初投稿としては悪くない感じがします。

#Next
色々な前処理や予測モデルを試していきたいです。
また、それぞれの予測モデルの理解も含めていきます。