【SIGNATE】ロジスティック回帰モデルの精度を上げよう

*この記事は「[【SIGNATE】本の知識だけでSIGNATEの練習問題に挑戦してみた](https://qiita.com/sakaidamasaru/items/d3c8a2f85d862c0a4042)」の続編です。*

# ロジスティック回帰モデルの精度向上

前回投稿した記事内で実装したロジスティック回帰モデルの精度を上げるために色々やってみた

### 標準化

前回の記事内で既に標準化は行っていたが、効果があったのかを確かめた

標準化していないトレーニングデータを用いてモデルをトレーニングした

```python
from sklearn.linear_model import LogisticRegression

lr = LogisticRegression(C=100.0, random_state=1)

# 標準化していないトレーニングデータ（learning_data）を用いてロジスティック回帰クラスを学習する
lr.fit(learning_data_X, learning_data_Y)
```

このモデルの精度は以下の通りであった

```python
# 正解データ（validation_data）を用いて精度を求める
lr.score(validation_data_X, validation_data_Y)
```
<img width="408" alt="スクリーンショット 2020-02-26 20.40.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546595/17a1b1c9-3104-7580-1fc9-669ea04c4241.png">
標準化した場合の精度が79.23%であったので、0.4%程度精度が上がっていた
（ほぼ誤差の範囲。各特徴量のデータの値の大きさにばらつきがないため、標準化は効果的ではないのだと思われる）

### 主成分分析による次元削減

特徴量が6つは多い気がしたので、次元削減のために主成分分析を行った

```python
import numpy as np

# 標準化したトレーニングデータ（learning_data_X_std）を用いて、共起行列を生成する
cov_mat = np.cov(learning_data_X_std.T)

# 固有値・固有ベクトルを計算する
eigen_vals, eigen_vecs = np.linalg.eig(cov_mat)
```

固有値は以下の通りであった

```python
# 固有値の値を確認する
eigen_vals
```
<img width="571" alt="スクリーンショット 2020-02-26 20.56.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546595/688732a4-ef9b-6491-01e9-6127e5699c70.png">
全ての固有値が1に近い値であり、次元削減はできなさそう

### カーネル主成分分析

ただの主成分分析では駄目そうなので、カーネル主成分分析を試してみた

```python
from sklearn.decomposition import KernelPCA

# カーネル主成分分析クラスのインスタンスを生成する
scikit_kpca = KernelPCA(n_components=6, kernel='rbf', gamma=15)

# 標準化したトレーニングデータ（learning_data_X_std）を用いて、カーネル行列を計算する
scikit_kpca.fit(learning_data_X_std)

# トレーニングデータと正解データを変換する
learning_data_X_std_kpca = scikit_kpca.transform(learning_data_X_std)
validation_data_X_std_kpca = scikit_kpca.transform(validation_data_X_std)
```

カーネル行列を用いて変換したトレーニングデータを用いてロジスティック回帰モデルを学習した

```python
from sklearn.linear_model import LogisticRegression

lr = LogisticRegression(C=100.0, random_state=1)

# 標準化+カーネル主成分分析によってデータ変換したトレーニングデータ（learning_data_X_std_kpca）を用いてロジスティック回帰クラスを学習する
lr.fit(learning_data_X_std_kpca, learning_data_Y)
```

このモデルの精度は以下の通りであった

```python
lr.score(validation_data_X_std_kpca, validation_data_Y)
```
<img width="484" alt="スクリーンショット 2020-02-26 21.13.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546595/5ceaf8a4-39bf-036a-725b-de60eb5862c6.png">
なんでアホになってんねん

### パラメータの最適化

標準化＋カーネル主成分分析によるデータ変換を行った結果、モデルの精度が下がってしまった
これはおそらくインプットパラメータ（標準化のC、カーネル主成分分析のγ）が不適であることが原因であろう

この2つのインプットパラメータを色々変化させた結果、C=500、γ=0.1で精度が83.84%まで高められることが分かった
<img width="480" alt="スクリーンショット 2020-02-26 21.33.46.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546595/8ad21d35-72cf-e172-8a98-40dfe70c5dc7.png">

# 他の分類器を試してみた

ロジスティック回帰の精度を向上させるために、他にどんな方法があるか思いつかなかったので
他の分類器だったらどうなるか試してみた

### 決定木

特徴量が離散値であり、かつ、取りうる値の数が少ないので、決定木を試してみた

```python
from sklearn.tree import DecisionTreeClassifier

tree = DecisionTreeClassifier(criterion='gini', max_depth=4, random_state=1)

# 標準化していないトレーニングデータを用いて決定木を学習する
tree.fit(learning_data_X, learning_data_Y)
```

このモデルの精度は以下の通りであった

```python
tree.score(validation_data_X, validation_data_Y)
```
<img width="424" alt="スクリーンショット 2020-02-26 21.50.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546595/0f21f4c0-bc92-95d2-f726-f2b3a59ba8f7.png">
めっちゃ精度ええやん

### ランダムフォレスト

決定木でかなりいい精度が出ていたので、ランダムフォレストも試してみた

```python
from sklearn.ensemble import RandomForestClassifier

forest = RandomForestClassifier(criterion='gini', n_estimators=25, random_state=1, n_jobs=2)

# 標準化していないトレーニングデータを用いてランダムフォレストを学習する
forest.fit(learning_data_X, learning_data_Y)
```

このモデルの精度は以下の通りであった

```python
forest.score(validation_data_X, validation_data_Y)
```
<img width="436" alt="スクリーンショット 2020-02-26 21.54.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546595/3d6c4be4-7df7-2798-27f8-e701d1d8bfb4.png">

# おわり
**分類器には得手不得手があるので、様々な分類器で問題にアプローチすることが大事**ということがよく理解できました