KaggleのTitanicでモデルを選別する（kaggle④）

#はじめに
初めて<b>Kaggle（カグル）</b>のコンペに参加してみたお話です。
[前回の「KaggleのTitanicで相関関係を確認する」](https://qiita.com/sudominoru/items/840e87cc77de29f10ca2)では、相関関係を調べて、Pclass（チケットクラス）、Sex（性別）、Fare（運賃）の3つの入力データを採用することにしました。
今回はいくつかのモデルを試してみたいと思います。


#目次
1.結果
2.利用するモデルについて
3.モデルの評価方法
4.モデルを試す
5.パラメータチューニング
6.Kaggleに提出する
7.まとめ

履歴

#1.結果

結果から言うと、スコアが少しあがり「0.77511」になりました。
上位58%（2019/12/29現在）という結果です。
再提出までの流れを見ていきたいと思います。


#2.利用するモデルについて
前回は、[scikit-learnのアルゴリズムシート](https://scikit-learn.org/stable/_static/ml_map.png)に従って「Linear SVC」を利用しました。
自分が機械学習を最初に学んだ[この本](https://www.amazon.co.jp/Python-%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-%E9%81%94%E4%BA%BA%E3%83%87%E3%83%BC%E3%82%BF%E3%82%B5%E3%82%A4%E3%82%A8%E3%83%B3%E3%83%86%E3%82%A3%E3%82%B9%E3%83%88%E3%81%AB%E3%82%88%E3%82%8B%E7%90%86%E8%AB%96%E3%81%A8%E5%AE%9F%E8%B7%B5-impress-gear/dp/4295003379/ref=dp_ob_title_bk)では、クラス分類問題について、scikit-learnの以下のモデルを取り上げています。
・sklearn.svm.LinearSVC
・sklearn.svm.SVC
・sklearn.ensemble.RandomForestClassifier
・sklearn.linear_model.LogisticRegression
・sklearn.linear_model.SGDClassifier

今回は、上記のモデルを試してみたいと思います。

#3.モデルの評価方法
モデルの評価は以下の手順になります。
1.トレーニングデータを使って学習する
2.テストデータを使って、予測する
3.予測した結果が正しいか確認する

KaggleのTitanicでは、トレーニングデータ [train.csv]（結果が分かるデータ）とテストデータ [test.csv]（結果が分からないデータ）があります。
2の「予測する」と、3の「確認する」をtest.csv を使うと毎回commitして提出しないと結果が分からないため非効率です。
結果が分かっているトレーニングデータ [train.csv]を、トレーニングデータ用データとテスト用データに分けることで効率的に評価することができます。
scikit-learnには、トレーニングデータとテストデータに分割する関数「train_test_split」が用意されています。

```python
from sklearn.model_selection import train_test_split

######################################
# トレーニングデータとテストデータを分ける
# Split training data and test data
######################################
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=1, shuffle=True)
```

以下のようなイメージです。
test_size=0.3だと、トレーニングデータとテストデータを「7:3」で分割します。

〇分割前のデータ

<table>
<tr><td></td><td>y</td><td colspan="3">x</td></tr>
<tr><td></td><td>Survived</td><td>Pclass</td><td>Sex</td><td>Fare</td></tr>
<tr><td>1</td><td>0</td><td>3</td><td>male</td><td>7.25</td></tr>
<tr><td>2</td><td>1</td><td>1</td><td>female</td><td>71.2833</td></tr>
<tr><td>3</td><td>1</td><td>3</td><td>female</td><td>7.925</td></tr>
<tr><td>4</td><td>1</td><td>1</td><td>female</td><td>53.1</td></tr>
<tr><td>5</td><td>0</td><td>3</td><td>male</td><td>8.05</td></tr>
<tr><td>6</td><td>0</td><td>3</td><td>male</td><td>8.4583</td></tr>
<tr><td>7</td><td>0</td><td>1</td><td>male</td><td>51.8625</td></tr>
<tr><td>8</td><td>0</td><td>3</td><td>male</td><td>21.075</td></tr>
<tr><td>9</td><td>1</td><td>3</td><td>female</td><td>11.1333</td></tr>
<tr><td>10</td><td>1</td><td>2</td><td>female</td><td>30.0708</td></tr>
</table>

〇分割後のトレーニングデータ

<table>
<tr><td></td><td>y_train</td><td colspan="3">x_train</td></tr>
<tr><td></td><td>Survived</td><td>Pclass</td><td>Sex</td><td>Fare</td></tr>
<tr><td>1</td><td>0</td><td>3</td><td>male</td><td>7.25</td></tr>
<tr><td>2</td><td>1</td><td>1</td><td>female</td><td>71.2833</td></tr>
<tr><td>4</td><td>1</td><td>1</td><td>female</td><td>53.1</td></tr>
<tr><td>5</td><td>0</td><td>3</td><td>male</td><td>8.05</td></tr>
<tr><td>6</td><td>0</td><td>3</td><td>male</td><td>8.4583</td></tr>
<tr><td>8</td><td>0</td><td>3</td><td>male</td><td>21.075</td></tr>
<tr><td>10</td><td>1</td><td>2</td><td>female</td><td>30.0708</td></tr>
</table>

〇分割後のテストデータ

<table>
<tr><td></td><td>y_test</td><td colspan="3">x_test</td></tr>
<tr><td></td><td>Survived</td><td>Pclass</td><td>Sex</td><td>Fare</td></tr>
<tr><td>3</td><td>1</td><td>3</td><td>female</td><td>7.925</td></tr>
<tr><td>7</td><td>0</td><td>1</td><td>male</td><td>51.8625</td></tr>
<tr><td>9</td><td>1</td><td>3</td><td>female</td><td>11.1333</td></tr>
</table>

続いて、学習と予測です。

scikit-learnのモデルには、学習するためのメソッド「fit」と、予測を評価するためのメソッド「score」が提供されています。
「fit」と「score」です。

```python
from sklearn.svm import LinearSVC
model = LinearSVC(random_state=1)

######################################
# 学習する
# training
######################################
model.fit(x_train, y_train)

######################################
# 予測した結果を評価する
# Evaluate predicted results
######################################
score = model.score(x_test, y_test)
```

「fit」は学習です。
「score」は「x_test」で結果を予測し、その結果と「y_test」と突き合わせて正解率を返します。
上記の場合、score は「0.753731343283582」になります。
75%の正解率という結果です。

#4.モデルを試す

いろいろなモデルを試し、scoreを比較することで、モデルの性能を評価できます。
「2.利用するモデルについて」のモデルを試してみます。

全体的なコードは以下です。

```python:準備
import numpy 
import pandas

# train.csvを読み込む
# Load train.csv
df = pandas.read_csv('/kaggle/input/titanic/train.csv')

##############################
# データ前処理
# 必要な項目を抽出する
# Data preprocessing 
# Extract necessary items
##############################
# 'Survived', 'Pclass', 'Sex', 'Fare'を抽出する
# Extract 'Survived', 'Pclass', 'Age', 'Fare'
df = df[['Survived', 'Pclass', 'Sex', 'Fare']]

##############################
# データ前処理
# ラベル（名称）を数値化する
# Data preprocessing 
# Digitize labels
##############################
from sklearn.preprocessing import LabelEncoder
# 性別をLabelEncoderを利用して数値化する
# Digitize gender using LabelEncoder
encoder_sex = LabelEncoder()
df['Sex'] = encoder_sex.fit_transform(df['Sex'].values)

##############################
# データ前処理
# 数値を標準化する
# Data preprocessing
# Standardize numbers
##############################
from sklearn.preprocessing import StandardScaler

# 標準化
# Standardize numbers
standard = StandardScaler()
df_std = pandas.DataFrame(standard.fit_transform(df[['Pclass', 'Fare']]), columns=['Pclass', 'Fare'])

# Fare を標準化
# Standardize Fare
df['Pclass'] = df_std['Pclass']
df['Fare'] = df_std['Fare']

from sklearn.model_selection import train_test_split

x = df.drop(columns='Survived')
y = df[['Survived']]
```

```python:トレーニングデータ、テストデータ作成
#######################################
# トレーニングデータとテストデータを分ける
# Split training data and test data
#######################################
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=1, shuffle=True)
y_train = numpy.ravel(y_train)
y_test = numpy.ravel(y_test)
```

```python:モデル評価
#######################################
# モデルを評価する
# Evaluate the model
#######################################
from sklearn.svm import LinearSVC
model = LinearSVC(random_state=1)
model.fit(x_train, y_train)
score = model.score(x_test, y_test)
score
```

「モデル評価」のモデルの定義部分を差し替えれば、いろいろなモデルで評価できます。
「2.利用するモデルについて」に記述したモデルを試してみます。
結果は以下になりました。

|モデル|score|
|:--|:--|
|sklearn.svm.LinearSVC|0.753|
|sklearn.svm.SVC|0.783|
|sklearn.ensemble.RandomForestClassifier|0.805|
|sklearn.linear_model.LogisticRegression|0.753|
|sklearn.linear_model.SGDClassifier|0.753|

ランダムフォレストが一番良いという結果になりました。
次は、ランダムフォレストモデルのパラメータを調整してみます。


#5.パラメータチューニング

パラメータの調整は scikit-learn にある グリッドサーチ（GridSearchCV）を利用します。
グリッドサーチは、指定されたパラメータを全パターンで評価し、最適なパラメータの組み合わせを突き止めてくれます。
ただし、全パターンを評価するため、パラメータを増やすほど処理に時間がかかります。
[ランダムフォレストのドキュメント](https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html)を確認し、以下のパラメータを調整することににします。

|パラメータ|パターン|
|:--|:--|
|criterion|gini / entropy|
|n_estimators|25 / 100 / 500 / 1000 / 2000|
|min_samples_split|0.5 / 2 / 4 / 10|
|min_samples_leaf|1 / 2 / 4 / 10|
|bootstrap|Ture / False|


「モデル評価」を以下の「グリッドサーチ」に入れ替えることで、グリッドサーチを実行できます。

```python:グリッドサーチ
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV
###############################################
# グリッドサーチで LogisticRegression のパラメータを試す
# Tuning LogisticRegression parameters with grid search
###############################################
pipe_svc = RandomForestClassifier(random_state=1)

param_grid = {'criterion':['gini','entropy'],
			  'n_estimators':[25, 100, 500, 1000, 2000],
			  'min_samples_split':[0.5, 2,4,10],
			  'min_samples_leaf':[1,2,4,10],
			  'bootstrap':[True, False]
			  }

grid = GridSearchCV(estimator=RandomForestClassifier(random_state=1), param_grid=param_grid)
grid = grid.fit(x_train, y_train)

print(grid.best_score_)
print(grid.best_params_)
```

以下の結果になりました。
自分の環境では、グリッドサーチの実行に10分程度かかりました。

```python:グリッドサーチ結果
0.8105939004815409
{'bootstrap': False, 'criterion': 'entropy', 'min_samples_leaf': 10, 'min_samples_split': 2, 'n_estimators': 100}
```

#6.Kaggleに提出する
グリッドサーチでチューニングしたパラメータを指定し、学習、予測してみましょう。
「トレーニングデータ、テストデータ作成」「グリッドサーチ」のコードを以下に書き換え、学習と予想を行います。

```python:学習、予想
##############################
# モデルの構築
# Model building
##############################
from sklearn.ensemble import RandomForestClassifier

# モデルを生成する
# Generate a model
model = RandomForestClassifier(n_estimators=100, \
                               criterion='entropy', \
                               min_samples_split=2, \
                               min_samples_leaf=10, \
                               bootstrap=False, \
                               random_state=1)

##############################
# 学習
# Trainig
##############################
y = numpy.ravel(y)
model.fit(x, y)

# test.csv を変換する
# convert test.csv
##############################
# test.csvを読み込む
# Load test.csv
df_test = pandas.read_csv('/kaggle/input/titanic/test.csv')

# Fare のNanを変換
# Convert Fare Nan to 0 
df_test = df_test.fillna({'Fare':0})

# 'PassengerId'を抽出する(結果と結合するため)
# Extract 'PassengerId'(To combine with the result)
df_test_index = df_test[['PassengerId']]

# 'Pclass', 'Sex', 'Fare'を抽出する
# Extract 'Pclass', 'Sex', 'Fare'
df_test = df_test[['Pclass', 'Sex', 'Fare']]

# 標準化
# Standardize
df_test_std = pandas.DataFrame(standard.transform(df_test[['Pclass', 'Fare']]), columns=['Pclass', 'Fare'])
df_test['Pclass'] = df_test_std['Pclass']
df_test['Fare'] = df_test_std['Fare']

# ラベル エンコーディング
# Label Encoding
df_test ['Sex'] = encoder_sex.transform(df_test ['Sex'].values)

##############################
# 結果を予想する
# Predict results
##############################
x_test = df_test.values
y_test = model.predict(x_test)

# PassengerId のDataFrameと結果を結合する
# Combine the data frame of PassengerId and the result
df_output = pandas.concat([df_test_index, pandas.DataFrame(y_test, columns=['Survived'])], axis=1)

# result.csvをカレントディレクトリに書き込む
# Write result.csv to the current directory
df_output.to_csv('result.csv', index=False)
```

上記をKaggleの環境で記述します。
「Run All」を実行し、result.csvが作成されることを確認します。

「Commit」⇒「Open Version」⇒「Submit to Competition」で提出します。
![20191229_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545343/943c1930-f721-fe7f-fd30-81ac0c19c599.png)

スコアが「0.77511」になりました。

#7.まとめ

今回は5種類のモデルを比較し、パラメータチューニングすることでスコアを少し上げることができました。
[次回](https://qiita.com/sudominoru/items/4c1d48093bbd3500dafb)は scikit-learn のいろいろなモデルから、より適したモデルを調べてみたいと思います。

#履歴
2019/12/29 初版公開
2020/01/01 次回のリンク追加
2020/01/03 ソースのコメント修正