【初心者】Kaggleのタイタニック号の生存者予測をやってみた。[part1-環境構築〜EDA]

#はじめに

なぜいまさらタイタニック号をやることにしたかというと、主にCV（コンピュータビジョン）でディープラーニングしかやってこなかった私は、特徴量エンジニアリングやDLではない機械学習のアルゴリズムも学びたいと思ったのがきっかけです。あとSeabornの使い方に慣れたい（切実）。ですので、Seabornのチュートリアルみたいな感じになるかもしれません。

記事の内容としては、kaggleのカーネルを複数読みながら自分なりにまとめる感じで書いています。

#１．環境構築
自分の研究室ではGPU搭載のマシンがないので、環境としてはGoogle Colaboratoryを使います。理由はクラウド上のインスタンスでしかも機械学習の環境はある程度揃っている、さらにやっぱりなんと言っても**無料でGPU＆TPUが使える！！**
使い方などはこちらの記事を参考にしました。
> [[Kaggle]0から本当に機械学習を理解するために学ぶべきこと～一流のデータサイエンティストを例に～](https://qiita.com/tomo_makes/items/b3c60b10f7b25a0a5935)

##1.1 Google Colaboratoryで自分のGoogleドライブをマウントする。
colabには90分ルールと12時間ルールがあるので、データセットとかをいちいちロードしなくてもいいようにするためにGoogleドライブをマウントします。そうすることによって外付けハードディスクのような感覚でcolabから自分のドライブにアクセスができ、インスタンスの再起動によってデータセットや、構築したモデルを失わずに済む。

下記のコードで簡単にマウントすることができます。

```python

#mount your google drive
from google.colab import drive
drive.mount('/content/drive')
```
##1.2 プロジェクトフォルダの作成

データ分析をするときのフォルダ構成をどうするのかは各自自分の好みの構成があると思うが、私はまだ初心者でしかもKaggleをはじめたばっかりだし、なにかテンプレートがあれば一番いいなと思って自分なりに調べてみたところ下記の素晴らしい記事と出会いました。
>[データ分析をするときのフォルダ構成をどうするのか問題について](https://www.st-hakky-blog.com/entry/2017/03/24/140738)

人それぞれの好みがあることも知ったので、まだ好みがない私はとりあえずcookiecutter Data scienceを使ってみた。コマンド一発で機械学習プロジェクトのディレクトリを作ってくれるのでとても便利だと思いました。

インストール方法などは[こちらの記事](https://qiita.com/Hironsan/items/4479bdb13458249347a1)を参考にしました。

というわけで私のフォルダ(kaggle_titanic)の構造は以下の通りです。

```text
├── LICENSE
├── Makefile           <- Makefile with commands like `make data` or `make train`
├── README.md          <- The top-level README for developers using this project.
├── data
│   ├── external       <- Data from third party sources.
│   ├── interim        <- Intermediate data that has been transformed.
│   ├── processed      <- The final, canonical data sets for modeling.
│   └── raw            <- The original, immutable data dump.
│
├── docs               <- A default Sphinx project; see sphinx-doc.org for details
│
├── models             <- Trained and serialized models, model predictions, or model summaries
│
├── notebooks          <- Jupyter notebooks. Naming convention is a number (for ordering),
│                         the creator's initials, and a short `-` delimited description, e.g.
│                         `1.0-jqp-initial-data-exploration`.
│
├── references         <- Data dictionaries, manuals, and all other explanatory materials.
│
├── reports            <- Generated analysis as HTML, PDF, LaTeX, etc.
│   └── figures        <- Generated graphics and figures to be used in reporting
│
├── requirements.txt   <- The requirements file for reproducing the analysis environment, e.g.
│                         generated with `pip freeze > requirements.txt`
│
├── src                <- Source code for use in this project.
│   ├── __init__.py    <- Makes src a Python module
│   │
│   ├── data           <- Scripts to download or generate data
│   │   └── make_dataset.py
│   │
│   ├── features       <- Scripts to turn raw data into features for modeling
│   │   └── build_features.py
│   │
│   ├── models         <- Scripts to train models and then use trained models to make
│   │   │                 predictions
│   │   ├── predict_model.py
│   │   └── train_model.py
│   │
│   └── visualization  <- Scripts to create exploratory and results oriented visualizations
│       └── visualize.py
│
└── tox.ini            <- tox file with settings for running tox; see tox.testrun.org

```

##1.3 Kaggle APIの設定とデータセットの用意
Kaggleからデータセットを取得するために必要。下記の記事を参考にしました。

> [Google Colab上でKaggleのデータをロード、モデル訓練、提出の全てを行う](https://qiita.com/katsu1110/items/a8d508a1b6f07bd3a243) 

kaggleから自分のkaggle.jsonをダウンロードし、.kaggleディレクトリを〜もとに作成、そしてパスを通します。

```python

!mkdir -p ~/.kaggle
!cp kaggle.json ~/.kaggle/
!chmod 600 /root/.kaggle/kaggle.json
```
データセットのダウンロード。ワークディレクトリの変更

```python
%cd kaggle_titanic/data/raw/
!kaggle competitions download -c titanic
#Changing work directory
%cd kaggle_titanic/
```


#2.　とりあえずデータをみてみよう！
やっぱり最初はEDA（Exploratory Data Analysis）ですね。
データ構造や種類などを理解しないと始まらないすもんね。
とうことでここからはSeabornのEDAの仕方をいろいろと見ながら考察していきます。

##2.1 データをロード
まずは基本ライブラリのインポートをしましょう。

```python
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

%matplotlib inline
sns.set()

```
そしてデータをロード

```python
# load datasets
train_df = pd.read_csv("./data/raw/train.csv")
test_df = pd.read_csv("./data/raw/test.csv")
```

##2.2 データをのぞき見しましょう

```python
train_df.head()
```
![Screen Shot 2019-03-08 at 14.46.53.png](https://qiita-image-store.s3.amazonaws.com/0/235725/2664a9bf-39e8-5c50-e59b-d34b9e580196.png)

次はデータフレームの統計情報を見てみよう

```python
train_df.describe()
```
![Screen Shot 2019-03-08 at 14.36.15.png](https://qiita-image-store.s3.amazonaws.com/0/235725/b2df5625-0429-37ea-438f-e3b8acad1fdc.png)

describe()で見た感じ、Ageあたりに欠損データがありそうなので全体のデータフレームで欠損データがどれくらいあるのかを下記の関数を使って見てみよう。

```python
def missing_table(df): 
        null_val = df.isnull().sum()
        percent = 100 * df.isnull().sum()/len(df)
        kesson_table = pd.concat([null_val, percent], axis=1)
        kesson_table_ren_columns = kesson_table.rename(
        columns = {0 : '欠損数', 1 : '%'})
        return kesson_table_ren_columns
```
![Screen Shot 2019-03-08 at 14.53.19.png](https://qiita-image-store.s3.amazonaws.com/0/235725/e99656db-e074-fe01-389e-c4fbc2084ed6.png)

Age, Cabin, Embarkedに欠損データがあったのでこれらのデータを埋めるか捨てるかをしなければならないだろう、、しかし今はEDAなのでただただデータを眺めます。

##2.3 Seaborn Countplots
SeabornのCountplotsを使ってカテゴリカルデータ（'Survived', 'Sex', 'Pclass', 'SibSp', 'Parch', 'Embarked'）の情報を見てみます。

```python
cols = ['Survived', 'Sex', 'Pclass', 'SibSp', 'Parch', 'Embarked']
nr_rows = 2
nr_cols = 3

fig, axs = plt.subplots(nr_rows, nr_cols, figsize=(nr_cols*3.5,nr_rows*3))

for r in range(0,nr_rows):
    for c in range(0,nr_cols):  
        
        i = r*nr_cols+c       
        ax = axs[r][c]
        sns.countplot(train_df[cols[i]], hue=train_df["Survived"], ax=ax)
        ax.set_title(cols[i], fontsize=14, fontweight='bold')
        ax.legend(title="survived", loc='upper center') 
        
plt.tight_layout()   
```

![Screen Shot 2019-03-08 at 15.19.58.png](https://qiita-image-store.s3.amazonaws.com/0/235725/ad1af637-a44c-285c-e688-4e701241e8bb.png)

このデータをみるといろいろと分かってきます。例えば
    
- 男性より女性のほうが生存する確率が高い。
    - やっぱり女性や子供は先に避難するからなのか
- Pclassが高いほど（クラスが１）生存する確率が高い、逆にPclassが低いと生存する確率は低い
    - お金持ちだとやっぱり先に救助されるのか笑
- 家族がいない人のほうが生存率が低い？
    - Parch,Sibsisが0人の人の生存率はだいたい2倍くらい違う
    - 家族連れの人たちは家族がいない人よりも生存率が高い
    - 家族が助けに来てくれるから？
- CとQの港から乗った人たちのほうがSの港から乗った人たちより生存率が低い？

##2.4 Seaborn Distplots
次はDistplots(分散情報をみるための関数)を使って性別、Pclass、Survivedについて年齢の分散を以下のコードを使って見ましょう。

```python
bins = np.arange(0, 80, 5)
g = sns.FacetGrid(df_train, row='Sex', col='Pclass', hue='Survived', margin_titles=True, size=3, aspect=1.1)
g.map(sns.distplot, 'Age', kde=False, bins=bins, hist_kws=dict(alpha=0.6))
g.add_legend()  
plt.show()  
```
![Screen Shot 2019-03-08 at 16.30.13.png](https://qiita-image-store.s3.amazonaws.com/0/235725/6ecbf9e1-0830-811d-0ec0-82811923486e.png)

```python
bins = np.arange(0, 80, 5)
g = sns.FacetGrid(train_df, col='Sex', hue='Survived', margin_titles=True, height=6, aspect=1.0)
g.map(sns.distplot, 'Age', kde=True, bins=bins, hist=False)
g.add_legend()  
plt.show()  
```
![Screen Shot 2019-03-12 at 11.44.56.png](https://qiita-image-store.s3.amazonaws.com/0/235725/94622743-42c4-8ad3-d277-14ad1834047f.png)


これらを見てわかること

- 男性はPclassが１のときまたは５歳以下のとき生存する確率が最も高いことがわかる。
- 女性の生存確率が一番低いのはPclass3で40歳以上のとき
- Pclass 3では、ほとんどの乗客は男性で15−35がもっとも多い
- 15歳〜30歳くらいの男性の生存するかくりつが低い

次は性別、Pclass、SurvivedについてFare（運賃）の分散を見てみます。

```python
train_df['Fare'].max()
#output: 512.3292
bins = np.arange(0, 550, 50)
g = sns.FacetGrid(train_df, row='Sex', col='Pclass', hue='Survived', margin_titles=True, height=3, aspect=2.0)
g.map(sns.distplot, 'Fare', kde=False, bins=bins,hist_kws=dict(alpha=0.6))
g.add_legend()  
plt.show()  
```


![Screen Shot 2019-03-12 at 13.44.28.png](https://qiita-image-store.s3.amazonaws.com/0/235725/6a5b983c-9097-80f8-f854-09f5137354e7.png)

##2.5 Bar and Box plots
### 2.5.1 Bar plots
Seabornのbarplotsはデフォルトではカテゴリの平均値とその信頼区間をプロットします。なので、もしSurvivedをy-valueとして選ぶとx-valueについてのSurvived rate(生き残る確率)を出すことができます。
例えば、x-valueをPclassとして選ぶと、各PclassのSurvival rateがプロットされる。

```python
sns.barplot(x='Pclass', y='Survived', data=train_df)
plt.ylabel("Survival Rate")
plt.title("Survival as function of Pclass")
plt.show()
```

![Screen Shot 2019-03-12 at 14.25.17.png](https://qiita-image-store.s3.amazonaws.com/0/235725/484d7c56-1c81-daaf-6b77-d9d11cca6a49.png)

これをみるとやっぱり、Pclassが高いほど生存率が高いことがわかる。
では、次は男女別でみてみよう。

```python
sns.barplot(x='Sex', y='Survived', hue='Pclass', data=train_df)
plt.ylabel("Survival Rate")
plt.title("Survival as function of Pclass and Sex")
plt.show()
```

![Screen Shot 2019-03-12 at 14.53.36.png](https://qiita-image-store.s3.amazonaws.com/0/235725/6e7beaf6-ea09-f048-ed49-100ee0ae104f.png)

生き残る確率が一番高いのはP1クラスの女性で約0.9割の確率で生き残っています。そして一番生き残るが低いのはP3クラスの男性です。

次は各港についてのSurvival rateを見てみます。

```python
sns.barplot(x='Embarked', y='Survived', hue='Pclass', data=train_df)
plt.ylabel("Survival Rate")
plt.title("Survival as function of Embarked Port")
plt.show()
```

![Screen Shot 2019-03-12 at 15.05.35.png](https://qiita-image-store.s3.amazonaws.com/0/235725/64353104-328e-e074-edbe-34a6e43f00b2.png)

Qの信頼区間が怪しいので各港での乗客数をみてみます。

```python
sns.countplot(x='Embarked', hue='Pclass', data=train_df)
plt.title("Count of Passengers as function of Embarked Port")
plt.show()
```

![Screen Shot 2019-03-12 at 15.08.34.png](https://qiita-image-store.s3.amazonaws.com/0/235725/4073133b-e5c3-0590-954a-bb3b115f1aa7.png)

S港から乗った乗客がほとんどP1クラスのチケットの割合を締めている事がわかる。そしてQ港からの乗客はほとんどP3クラスだとわかる。あと、S港の乗客が全乗客の割合を大きく占めている。


###2.5.2 Box plots

Boxplotでは中央値、外れ値などさまざまな分散情報が可視化できます。

<img width="691" alt="Screen Shot 2019-03-12 at 15.24.00.png" src="https://qiita-image-store.s3.amazonaws.com/0/235725/77fee9f0-3141-44fb-e9a0-06e27e9cdacc.png">

各港の年齢についてboxplotをしてみます。

```python
sns.boxplot(x='Embarked', y='Age', data=train_df)
plt.title("Age distribution as function of Embarked Port")
plt.show()
```

![Screen Shot 2019-03-12 at 15.26.23.png](https://qiita-image-store.s3.amazonaws.com/0/235725/7d72718c-2795-1c2c-bd0f-eb3b1d8f25f2.png)

##2.6 Swarm and Violin plots 

SwarmとViolin plotsはcountplotsとdistplotsと同じようなデータをプロットできます。しかし、たまに他のプロット方法では見逃してしまう特徴を表すことができます。

では実装してみます。まずは年齢とPクラスについてのSurvivedの分散をSwarmとViolinを使って見てみます。


```python
#choose color
cm_surv = ["darkgrey" , "lightgreen"]

#plot swarm
fig, ax = plt.subplots(figsize=(13,7))
sns.swarmplot(x='Pclass', y='Age', hue='Survived', split=True, data=train_df , palette=cm_surv, size=7, ax=ax)
plt.title('Survivals for Age and Pclass ')
plt.show()

#plot violin
fig, ax = plt.subplots(figsize=(13,7))
sns.violinplot(x="Pclass", y="Age", hue='Survived', data=train_df, split=True, bw=0.05 , palette=cm_surv, ax=ax)
plt.title('Survivals for Age and Pclass ')
plt.show()
```

![Screen Shot 2019-03-12 at 15.50.22.png](https://qiita-image-store.s3.amazonaws.com/0/235725/43d9caa0-0389-fd4b-3815-dba1afb3a694.png)

これをみると子供の生存確率が一番高いのはPclass2とういことがすぐに分かる。また40歳以上の乗客が生き残る確率が一番高いのはPclass1で一番低いのはPclass３。

violin plotはswarmと同じような内容を表すことができる。
![Screen Shot 2019-03-12 at 15.50.39.png](https://qiita-image-store.s3.amazonaws.com/0/235725/cc103888-04dc-5d99-e433-97a8ac0d302c.png)

そして一応性別べつでも見てみます。

```python
g = sns.catplot(x="Pclass", y="Age", hue="Survived", col="Sex", data=train_df, kind="swarm", dodge=True, palette=cm_surv, height=7, aspect=.9, s=7)
```

![Screen Shot 2019-03-12 at 16.00.20.png](https://qiita-image-store.s3.amazonaws.com/0/235725/13b48a7e-9c3e-d83a-9f59-a35afc6fe94c.png)

やっぱり女性のほうが圧倒的に生存する確率が高いですね。

---
そしてEDAはここまでにしておきたいと思います。
実際にデータを可視化することでだいぶそのデータのことがわかるようになりますね。EDAの仕方もたくさんあるのでも将来もう少し勉強したいと思います。
とりあえず今はここまでにしておきます。

***part2はいよいよ特徴量エンジニアリングとデータの前処理に入っていきます。***