【Python】初めての データ分析・機械学習（Kaggle）

#はじめに
就職間近（大学４年の春休み）になって、急遽データサイエンティストになりたいと思い、とりあえずKaggleに取り組み始めました。

今回取り組んだのは、[**Kaggle**](https://www.kaggle.com/)のチュートリアルである「[**Titanic**](https://www.kaggle.com/c/titanic/overview)」の問題です。

研究で統計解析の経験はあるが、機械学習は全くわからない状態からなので、めちゃくちゃ優秀な方のコードを参考にして勉強することにしました！

ちなみに、参考にしたのがこちら
[✔︎Introduction to Ensembling/Stacking in Python](https://www.kaggle.com/arthurtok/introduction-to-ensembling-stacking-in-python)
Notebookで「Most voted」と評されていたコードです。(2020.3.10時点)

あと、上記のコードを参考にしたこちらの記事も参考にしました笑
[Pythonでアンサンブル(スタッキング)学習 & 機械学習チュートリアル in Kaggle](https://qiita.com/hkthirano/items/2c35a81fbc95f0e4b7c1)


#Introduction
今回取り組むタイタニック号のコンペの内容は、年齢、性別、同室者数、部屋のクラス、生死などの乗客に関するデータが与えれます。

そのデータを元に、
**データの前処理
→データの可視化
→スタッキングモデル構築
→テストデータ
→評価**

といった流れで、最後にはテストデータから構築したモデルを使って乗客の生死の予測をします。この予測がどれくらいあっているかもスコアの基準になります。

かなりボリュームがあるので本記事では**「前処理」・「データの可視化」**に絞ります！

モデル構築以降は次回の記事に載せます！
続編記事はこちら↓↓↓
[【Python】初めての データ分析・機械学習（Kaggle）〜Part2〜](https://qiita.com/Julio_dev/items/4754a8dc545b7023e8c1)

では、早速データの前処理に取り掛かります！！

#データの前処理
###ライブラリのインポート
今回使用するライブラリをざっくり

- 数学的、統計的処理： numpy, pundas
- 正規表現操作（指定した形の言葉や数値の検索だったり置き換えだったり）: [re](https://www.lifewithpython.com/2014/10/re-regular-expression.html)
- いろんなモデルを持ってるよ~: [sklearn](https://techacademy.jp/magazine/17375)
- 勾配ブースティング決定木のアルゴリズム： [XGboost](http://tekenuko.hatenablog.com/entry/2016/09/22/220814)
- グラフや図: matplotlib, seaborn, plotly
- 警告の表示/非表示: warnings
- ５つの基礎モデル
    - [RandomForestClassifier](https://qiita.com/mshinoda88/items/8bfe0b540b35437296bd)
    - [AdaBoostClassifier](https://qiita.com/kibinag0/items/2e6740c58c1f2d2e119e)
    - [GradientBoostingClassifier](https://qiita.com/temy13/items/a69a20f2c0d3cf11627c)
    - [ExtraTreesClassifier](https://future-chem.com/ames-random-forest/)
    - [SVC](http://neuro-educator.com/ml3/)
- これらの５つのモデルライブラリを同時に適応するのが[Kfold](https://qiita.com/kibinag0/items/1a29db61fcb8c527d952)


```python:import_library.py
import pandas as pd
import numpy as np
import re
import sklearn
import xgboost as xgb
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline

import plotly.offline as py
py.init_notebook_mode(connected=True)
import plotly.graph_objs as go
import plotly.tools as tls

import warnings
warnings.filterwarnings('ignore')

# 5つのモデル
from sklearn.ensemble import (RandomForestClassifier, AdaBoostClassifier, 
                              GradientBoostingClassifier, ExtraTreesClassifier)
from sklearn.svm import SVC

#複数の機械学習ライブラリを同時に適応する
from sklearn.cross_validation import KFold
```


###データの取得
```python:import_data.py
train = pd.read_csv('../input/train.csv')
test = pd.read_csv('../input/test.csv')

#乗客のIDをPassengerIDに保持させる
PassengerId = test['PassengerId']

train.head(3)
```
出力
<img width="978" alt="スクリーンショット 2020-03-10 16.13.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/383306/1d3cb07c-89df-aebe-beab-0f8d9258fd22.png">

データの説明

- PassengerId:乗客のID
- Survived:生死フラグ（生き残った場合：１, 亡くなった場合:0）
- Pclass:チケットクラス
- Name：乗客の名前
- Sex:性別
- Age:年齢
- SibSp:同乗している兄弟/配偶者
- Parch:同乗している両親/子供
- fare:料金
- cabin:客室番号
- Embarked:乗船した港

###特徴量エンジニアリング
取得したデータを分析しやすいように加工していきます。
機械学習において、この**前処理はかなり重要**らしいので、長いけど頑張ります！！

基本的には、欠損値（値がない）や文字データを全て数値データに変換します。

```python:FeatureEngineering.py
full_data = [train, test]

#乗客の名前の長さ
train['name_length'] = train['name'].apply(len)
test['name_length'] = test['name'].apply(len)

#客室番号データがあるなら1を、欠損値なら0を
train['Has_Cabin'] = train['Cabin'].apply(lambda x: 0 if type(x) == float else 1)
test['Has_Cabin'] = test['Cabin'].apply(lambda x: 0 if type(x) == float else 1)

#家族の大きさをタイタニックに同乗している"兄弟/配偶者の数"と"親/子供の数"から定義する
for dataset in full_data:
    dataset ['FamilySize'] = dataset['Sibsp'] + dataset['Parch'] +1

#家族がいないなら"IsAlone"が1
for dataset in full_data:
    dataset['IsAlone'] = 0
    dataset.loc[dataset['FamilySize'] == 1, 'IsAlone'] = 1

#出港地の欠損値を一番多い'S'としておく
for dataset in full_data:
    dataset['Embarked'] = dataset['Embarked'].fillna('S')

#料金の欠損値を中央値としておく
#料金を大きく4つのグループに分ける
for dataset in full_data:
    dataset['Fare'] = dataset['Fare'].fillna(train['Fare'].median())
train['CategoricalFare'] = pd.qcut(train['Fare'], 4)

#年齢を５つのグループに分ける
for dataset in full_data:
    age_avg = dataset['Age'].mean()
    age_std = dataset['Age'].std()
    age_null_count = dataset['Age'].isnull().sum()
    #欠損値に入れるランダム値のリスト
    #平均値から偏差分だけ大きいor小さい値を用いる
    age_null_random_list = np.random.randint(age_avg - age_std, age_avg + age_std, size = age_null_count)
    dataset['Age'][np.isnan(dataset['Age'])] = age_null_random_list
    #データをint型に変換
    dataset['Age'] = dataset['Age'].astype(int)

train['CategoricalAge'] = pd.qcut(train['Age'],5)

#名前を取り出す関数get_titleの定義
def get_title(name):
    title_search = re.search('([A-Za-z]+)\.',name)
    #名前があれば取り出して返す
    if title_search:
       return title_search.group(1)
    return ""

#関数get_titleを使う
for dataset in ftll_data:
    dataset['Title'] = dataset['Name'].apply(get_title)

    #名前の記入ミス部分の修正
    dataset['Title'] = dataset['Title'].replace(['Lady', 'Countess','Capt', 'Col','Don', 'Dr', 'Major', 'Rev', 'Sir', 'Jonkheer', 'Dona'], 'Rare')

    dataset['Title'] = dataset['Title'].replace('Mlle', 'Miss')
    dataset['Title'] = dataset['Title'].replace('Ms', 'Miss')
    dataset['Title'] = dataset['Title'].replace('Mme', 'Mrs')

for dataset in full_data:
    # 女なら０、男なら１
    dataset['Sex'] = dataset['Sex'].map( {'female': 0, 'male': 1} ).astype(int)

    # 名前の5種類にラベル付
    title_mapping = {"Mr": 1, "Miss": 2, "Mrs": 3, "Master": 4, "Rare": 5}
    dataset['Title'] = dataset['Title'].map(title_mapping)
    dataset['Title'] = dataset['Title'].fillna(0)

    # 出港地の3種類にラベル付
    dataset['Embarked'] = dataset['Embarked'].map( {'S': 0, 'C': 1, 'Q': 2} ).astype(int)

    # 料金を４つのグループに分ける
    dataset.loc[ dataset['Fare'] <= 7.91, 'Fare']                               = 0
    dataset.loc[(dataset['Fare'] > 7.91) & (dataset['Fare'] <= 14.454), 'Fare'] = 1
    dataset.loc[(dataset['Fare'] > 14.454) & (dataset['Fare'] <= 31), 'Fare']   = 2
    dataset.loc[ dataset['Fare'] > 31, 'Fare']                                  = 3
    dataset['Fare'] = dataset['Fare'].astype(int)

    # 年齢を5つのグループに分ける
    dataset.loc[ dataset['Age'] <= 16, 'Age']                          = 0
    dataset.loc[(dataset['Age'] > 16) & (dataset['Age'] <= 32), 'Age'] = 1
    dataset.loc[(dataset['Age'] > 32) & (dataset['Age'] <= 48), 'Age'] = 2
    dataset.loc[(dataset['Age'] > 48) & (dataset['Age'] <= 64), 'Age'] = 3
    dataset.loc[ dataset['Age'] > 64, 'Age'] = 4 ;

# 必要ない特徴を削除
drop_elements = ['PassengerId', 'Name', 'Ticket', 'Cabin', 'SibSp']
train = train.drop(drop_elements, axis = 1)
train = train.drop(['CategoricalAge', 'CategoricalFare'], axis = 1)
test  = test.drop(drop_elements, axis = 1)

```

勉強になったコーディング

- lambda関数の使い方
- fillna()
- pandasのqcut
- map関数
- if文を使わず、loc[]の[]内でTrueの場合のみ値を入力
- axis = 1

#データの可視化
やっと前処理が終わりました！！
ちゃんと全てのデータが数値データになっているか確認してみましょう！

```python:visualize.py
train.head(3)
```

<img width="714" alt="スクリーンショット 2020-03-10 17.25.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/383306/addf0bed-2460-6b31-130d-d45db9c839b0.png">

###ピアソン相関ヒートマップ(Peason Correlation Heatmap)
特徴量同士の相関をヒートマップにて確認します。

```python:heatmap.py
colormap = plt.cm.RdBu
plt.figure(figsize = (14,12))
plt.title('Peason Correlation of Features', y = 1.05, size = 15)
sns.heatmap(train.astype(float).corr(), linewidths=0.1, vmax=1.0, square = True, cmap=colormap, linecolor='white', annot=True)
```

<img width="755" alt="スクリーンショット 2020-03-10 17.32.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/383306/479dfdd1-bcf9-c76b-a075-8dc9b0043d30.png">

このプロットから、そこまで特徴量が互いに強く相関していないことがわかります。

特徴量が互いに独立
→無駄な特徴がない
→学習モデルを構築する上で重要
(ParchとFamilySizeは比較的相関が強いですが、そのまま残しておきます。)

###ペアプロット(PairPlot)
ある特徴から別の特徴へのデータの分布

```python:PairPlot.py
g = sns.pairplot(train[[u'Survived', u'Pclass', u'Sex', u'Age', u'Parch', u'Fare', u'Embarked',
       u'FamilySize', u'Title']], hue='Survived', palette = 'seismic',size=1.2,diag_kind = 'kde',diag_kws=dict(shade=True),plot_kws=dict(s=10) )
g.set(xticklabels=[])
```

<img width="720" alt="スクリーンショット 2020-03-10 17.40.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/383306/e5a2a2be-b704-06e4-7d58-14bf79a7e777.png">

#まとめ
本記事では、Kaggleのチュートリアルの「Titanic」に取り組みました。
流れとしては、

1. ライブラリのインポート
2. データの取得
3. データの前処理
   - 欠損値をなくす（平均値に近い値をランダムに挿入等）
   - データの等分
   - カテゴリーデータを数値に変換
4. データの可視化
   - ピアソン相関ヒートマップ
   - ペアプロット

ここまででも結構大変でしたが、ここからがモデル構築の本番なので引き続き頑張ります！！