【SIGNATE】本の知識だけでSIGNATEの練習問題に挑戦してみた

書籍「［第2版］Python機械学習プログラミング 達人データサイエンティストによる理論と実践」から得た知識を基に、
SIGNATEの練習問題に挑戦してみた

### 開発環境
- MacOS Catalina 10.15.3
- Anaconda Navigator 1.9.7
- Python 3.7
- Jupiter Notebook 6.0.1

### 今回挑戦した練習問題

[【練習問題】自動車の評価](https://signate.jp/competitions/122)

- 6つの自動車の属性データから、評価値（unacc, acc, good, vgood）を予測する
- 属性データ（特徴量）は以下の6つ

| 属性名 | 説明 |
|:--|:--|
| buying | 車の売値（vhigh, high, med, low） |
| maint | 整備代（vhigh, high, med, low） |
| doors | ドアの数（2, 3, 4, 5, more.） |
| persons | 定員（2, 4, more.） |
| lug_boot | トランクの大きさ（small, med, big.） |
| safety | 安全性（low, med, high） |

# 問題を解いてみた

### まずはデータセットの内容を確認

```python
# データセットを読み込むためにpandasをインポートする
import pandas as pd

# pandasのread_csvメソッドを用いてトレーニングデータ（train.tsv）を読み込む
# トレーニングデータはサイトからダウンロード済み
train_data = pd.read_csv('./train.tsv', delimiter='\t')

# トレーニングデータを表示
train_data
```

<img width="437" alt="スクリーンショット 2020-02-24 21.48.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546595/842d7fd9-eecd-59ad-3d9c-72bafa2319f9.png">

特徴量の文字列データは数値に変換すべしと本に書いてあったので、データの文字列を数値に変換する
　※今回用いたデータセットに含まれる特徴量は全て**順序特徴量**に分類されるものなので、単純に文字列を順序通りに数値に変換した

```python
# 各特徴量の変換用の辞書を設定する
buying_mapping = {'vhigh': 4, 'high': 3, 'med': 2, 'low': 1}
maint_mapping = {'vhigh': 4, 'high': 3, 'med': 2, 'low': 1}
doors_mapping = {'5more': 5, '4': 4, '3': 3, '2': 2}
persons_mapping = {'more': 6, '4': 4, '2': 2}
lug_boot_mapping = {'big': 3, 'med': 2, 'small': 1}
safety_mapping = {'high': 3, 'med': 2, 'low': 1}

# クラスラベル（class）の変換用の辞書を設定する
class_mapping = {'vgood': 4, 'good': 3, 'acc': 2, 'unacc': 1}

# トレーニングデータの各特徴量を変換する
train_data['buying'] = train_data['buying'].map(buying_mapping)
train_data['maint'] = train_data['maint'].map(maint_mapping)
train_data['doors'] = train_data['doors'].map(doors_mapping)
train_data['persons'] = train_data['persons'].map(persons_mapping)
train_data['lug_boot'] = train_data['lug_boot'].map(lug_boot_mapping)
train_data['safety'] = train_data['safety'].map(safety_mapping)

# トレーニングデータのクラスラベル（class）を変換する
train_data['class'] = train_data['class'].map(class_mapping)

# 変換後のトレーニングデータを表示
train_data
```

<img width="427" alt="スクリーンショット 2020-02-24 22.01.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546595/7d451345-715a-d33e-c89d-f7a5b00cdbcc.png">

変換完了

トレーニングデータを特徴量とクラスラベルに分ける

```python
# pandasのilocメソッドを用いてトレーニングデータを特徴量（train_data_X）とクラスラベル（train_data_Y）に分離する
# idは学習に用いないため別に保管する
train_data_X = train_data.iloc[:,2:]
train_data_Y = train_data.iloc[:,1:2]
train_data_id = train_data.iloc[:,0:1]
```

最後に、トレーニングデータを学習用データと検証用データに分割する

```python
from sklearn.model_selection import train_test_split

# トレーニングデータを学習用データ（learning_data）と検証用データ（learning_data）に分割する
learning_data_X, validation_data_X, learning_data_Y, validation_data_Y = train_test_split(
    train_data_X, train_data_Y, test_size=0.3, random_state=1, stratify=train_data_Y)
```

これで学習のための準備はできた

### とりあえずロジスティック回帰でやってみた

ロジスティック回帰が一番簡単そうだったので、とりあえずロジスティック回帰でやってみた

特徴量はスケーリングすべしと本に書いてあったので、まずは特徴量の標準化を行う

```python
from sklearn.preprocessing import StandardScaler

stdsc = StandardScaler()

stdsc.fit(learning_data_X)

# トレーニングデータの特徴量の標準化を行う
learning_data_X_std = stdsc.transform(learning_data_X)
validation_data_X_std = stdsc.transform(validation_data_X)
```

標準化前のデータ（learning_data_X）はこんな感じ
<img width="365" alt="スクリーンショット 2020-02-24 22.23.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546595/fa96426e-1d84-5bd7-2190-8c8caae4808b.png">
標準化後のデータ（learning_data_X_std）はこんな感じ
<img width="633" alt="スクリーンショット 2020-02-24 22.23.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546595/c800f9fb-487b-619e-56a9-fefb14373720.png">

データを見てもよく分からないが、標準化できたっぽい

学習用データを用いてロジスティック回帰クラスを学習する

```python
from sklearn.linear_model import LogisticRegression

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

# 標準化した学習用データを用いてロジスティック回帰クラスを学習する
lr.fit(learning_data_X_std, learning_data_Y)
```

最後に、検証用データを用いて予測する

```python
score = lr.score(validation_data_X_std, validation_data_Y)
score
```

<img width="511" alt="スクリーンショット 2020-02-24 22.30.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546595/0520c1f0-6301-eb71-c2d9-6cb55c8cd6be.png">

今回作成したモデルのスコアは79.23%
ちなみに、SIGNATEではこの問題に対するモデルのランキングを公表しており、現時点での1位は100%、100位で96.875%
（今回作ったモデル、絶望的に精度悪いな。。）

本をちょろっと読んだだけだとまだまだ駄目やね。精進しなければ。

### おわり
今回のロジスティック回帰のモデルはハイパーパラメータ（C）の最適化も正則化項の最適化も行っていません
（C=1.0で計算したらscoreが77.69%に下がったのでひょっとしたら奇跡的にええ感じのパラメータを選択したかもしれませんが）

まだまだ改良の余地があるので、今後このモデルを改良していきます
（とりあえず90%のscoreが出るまで頑張りますか）