KaggleのTitanicでscikit-learnの全モデルを試す（kaggle⑤）

#はじめに
初めて<b>Kaggle（カグル）</b>のコンペに参加してみたお話です。
[前回の「KaggleのTitanicでモデルを選別する」](https://qiita.com/sudominoru/items/1c21cf4afaf67fda3fee)では、いくつかのモデルを評価してスコアを少し上げることができました。
今回は scikit-learn の全モデルを試してみたいと思います。


#目次
1.結果
2.scikit-learnの全モデルについて
3.交差検証
4.全モデルを交差検証で評価する
5.パラメータチューニング
6.Kaggleに提出する
7.まとめ

履歴

#1.結果

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

#2.scikit-learnの全モデルについて

scikit-learnの全モデルは「all_estimators」で取得することができます。
取得するときに「type_filter」のパラメータで以下の4つから絞り込みを行うことができます。
「classifier / regressor / cluster / transformer」
今回は分類問題ですので「classifier 」でフィルターします。

```python
from sklearn.utils.testing import all_estimators
all_estimators(type_filter="classifier")
```

#3.交差検証

上で取得したモデルに対して「交差検証」で検証を行ってみましょう。
今回は「K-分割交差検証」を行います。
K-分割交差検証は、まずトレーニングデータをK個に分割します。そして、そのうちの1つをテストデータとし、残った K − 1 個をトレーニングデータとします。
 K − 1 個のトレーニングデータで学習し、残ったテストデータで評価します。
これを k 回繰り返し、得られた k 回の結果（score）を平均してモデルを評価する方法です。
scikit-learnに、K-分割交差検証のクラスが用意されています。
「KFold」と「cross_validate」です。

```python
from sklearn.model_selection import KFold
from sklearn.model_selection import cross_validate
kf = KFold(n_splits=3, shuffle=True, random_state=1)
scores = cross_validate(model, x_train, y_train, cv=kf, scoring=['accuracy'])
```

KFoldの「n_splits」で何分割するかを指定します。
cross_validateでトレーニングデータとKFold、およびscoringの方法を指定します。
cross_validateの戻り値には、scoringで指定した評価が返却されます。返却値はn_splitsで分割した分だけ配列で返却されます。

#4.全モデルを交差検証で評価する

それでは、全モデルをK-分割交差検証で評価してみたいと思います。
コードは以下です。「準備」のコードは今までと同じです。

```python:準備
import numpy 
import pandas 

##############################
# データ前処理
# 必要な項目を抽出する
# Data preprocessing
# Extract necessary items
##############################
# train.csvを読み込む
# Load train.csv
df = pandas.read_csv('/kaggle/input/titanic/train.csv')
df = df[['Survived', 'Pclass', 'Sex', 'Fare']]
```

```python:準備
from sklearn.preprocessing import LabelEncoder
##############################
# データ前処理
# ラベル（名称）を数値化する
# Data preprocessing
# Digitize labels
##############################
#df = pandas.get_dummies(df)
encoder_sex = LabelEncoder()
df['Sex'] = encoder_sex.fit_transform(df['Sex'].values)
```

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

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

df['Pclass'] = df_std['Pclass']
df['Fare'] = df_std['Fare']
```

```python:K-分割交差検証
import sys
from sklearn.model_selection import KFold
from sklearn.model_selection import cross_validate
from sklearn.utils.testing import all_estimators
##############################
# 全モデルでK-分割交差検証を行う
# K-fold cross-validation with all estimators.
##############################
x_train = df.drop(columns='Survived').values
y_train = df[['Survived']].values
y_train = numpy.ravel(y_train)

kf = KFold(n_splits=3, shuffle=True, random_state=1)

writer = open('./all_estimators_classifier.txt', 'w', encoding="utf-8")
writer.write('name\taccuracy\n')

for (name,Estimator) in all_estimators(type_filter="classifier"):

    try:
        model = Estimator()
        if 'score' not in dir(model):
            continue;
        scores = cross_validate(model, x_train, y_train, cv=kf, scoring=['accuracy'])
        accuracy = scores['test_accuracy'].mean()
        writer.write(name + "\t" + str(accuracy) + '\n')
    except:
        print(sys.exc_info())
        print(name)
        pass

writer.close()
```

「all_estimators(type_filter="classifier")」で分類問題のモデルを取得し、ループしています。
「if 'score' not in dir(model):」でscoreを持っているモデルのみを対象にしています。
「cross_validate」で交差検証を評価します。パラメータに上で指定した「KFold」を指定します。
モデル名と評価の値を「all_estimators_classifier.txt」というファイル名に出力します。

実行してみます。
処理が完了すると「all_estimators_classifier.txt」が出力されます。
中身を見てみましょう。
モデル名が30個ほど出力されています。
「accuracy」が大きい順に10個のモデルをピックアップすると以下になりました。

|name|accuracy|
|:--|--:|
|ExtraTreeClassifier|0.82155|
|GradientBoostingClassifier|0.82043|
|HistGradientBoostingClassifier|0.81706|
|DecisionTreeClassifier|0.81481|
|ExtraTreesClassifier|0.81481|
|RandomForestClassifier|0.80920|
|GaussianProcessClassifier|0.80471|
|MLPClassifier|0.80471|
|KNeighborsClassifier|0.80022|
|LabelPropagation|0.80022|

[前回](https://qiita.com/sudominoru/items/1c21cf4afaf67fda3fee)の「RandomForestClassifier」より正解率が高いモデルが5つあります。

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

上位5つのモデルをそれぞれグリッドサーチでパラメータを確認してみます。
以下になりました。

|モデル|パラメータ|
|:--|:--|
|ExtraTreeClassifier|criterion='gini', min_samples_leaf=10, min_samples_split=2, splitter='random'|
|GradientBoostingClassifier|learning_rate=0.2, loss='deviance', min_samples_leaf=10, min_samples_split=0.5, n_estimators=500|
|HistGradientBoostingClassifier|learning_rate=0.05, max_iter=50, max_leaf_nodes=10, min_samples_leaf=2|
|DecisionTreeClassifier|criterion='entropy', min_samples_split=2, min_samples_leaf=1|
|ExtraTreesClassifier|n_estimators=25, criterion='gini', min_samples_split=10, min_samples_leaf=2, bootstrap=True|

#6.Kaggleに提出

それぞれのモデルでKaggleに提出してみます。
パラメータはグリッドサーチで調べたパラメータにします。
スコアは以下になりました。

|モデル|score|
|:--|:--|
|ExtraTreeClassifier|0.78947|
|GradientBoostingClassifier|0.75598|
|HistGradientBoostingClassifier|0.77990|
|DecisionTreeClassifier|0.77511|
|ExtraTreesClassifier|0.78468|

ExtraTreeClassifier が一番良いscoreになり「0.78947」という結果になりました。


#7.まとめ

scikit-learn の全モデルを交差検証で評価しました。
今回の入力データの場合は、ExtraTreeClassifierが最もスコアが良く
「0.78947」という結果になりました。
[次回](https://qiita.com/sudominoru/items/3e48a2daa76c085c0777)は、データを目視で確認して見たいと思います。
生データを確認することで、スクリーニングなどにより、さらに入力データの精度を上げられるか調べてみたいと思います。


#参考
[最適なモデル選びall_estimators()](https://betashort-lab.com/%E3%83%87%E3%83%BC%E3%82%BF%E3%82%B5%E3%82%A4%E3%82%A8%E3%83%B3%E3%82%B9/%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92/%E6%9C%80%E9%81%A9%E3%81%AA%E3%83%A2%E3%83%87%E3%83%AB%E9%81%B8%E3%81%B3all_estimators/)
[Python: scikit-learn の cross_validate() 関数で独自の評価指標を計算する](https://blog.amedama.jp/entry/sklearn-cv-custom-metric)
[sklearnの交差検証の種類とその動作](https://qiita.com/chorome/items/54e99093050a9473a189)


#履歴
2020/01/01 初版公開
2020/01/29 次回のリンク追加