機械学習PJで最低限やっておきたいこと

最近は機械学習関連の書籍やチュートリアルが充実してきており、モデルをとりあえず作ってみることはとても容易になっていますが、そうしてできたモデルと製品投入できる品質のものとの間の隔たりは小さくありません。そこを埋めるために最低限やっておきたいことのまとめです。

考慮すべき点のそれぞれについて深く掘り下げるというよりも、現状を俯瞰して足りない視点を補うために利用することを想定しました。

<img src="https://qiita-image-store.s3.amazonaws.com/0/293831/d9bdb428-3794-beda-f387-28d153f9c358.jpeg" width="500px">

チェックすべきポイントはカテゴリに分けると以下のようになります。

- [テスト(検証)](https://qiita.com/jyx/items/8f8bcd5ec5facf6b3afb#%E3%83%86%E3%82%B9%E3%83%88%E6%A4%9C%E8%A8%BC)
    - [交差検証](https://qiita.com/jyx/items/8f8bcd5ec5facf6b3afb#%E4%BA%A4%E5%B7%AE%E6%A4%9C%E8%A8%BC)
    - [学習曲線](https://qiita.com/jyx/items/8f8bcd5ec5facf6b3afb#%E5%AD%A6%E7%BF%92%E6%9B%B2%E7%B7%9A)
- [データセット](https://qiita.com/jyx/items/8f8bcd5ec5facf6b3afb#%E3%83%87%E3%83%BC%E3%82%BF%E3%82%BB%E3%83%83%E3%83%88)
    - [特徴量の選定](https://qiita.com/jyx/items/8f8bcd5ec5facf6b3afb#%E7%89%B9%E5%BE%B4%E9%87%8F%E3%81%AE%E9%81%B8%E5%AE%9A)
    - [サンプリングバイアス](https://qiita.com/jyx/items/8f8bcd5ec5facf6b3afb#%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AA%E3%83%B3%E3%82%B0%E3%83%90%E3%82%A4%E3%82%A2%E3%82%B9)
    - [データ量](https://qiita.com/jyx/items/8f8bcd5ec5facf6b3afb#%E3%83%87%E3%83%BC%E3%82%BF%E9%87%8F)
- [トレーニング(訓練)](https://qiita.com/jyx/items/8f8bcd5ec5facf6b3afb#%E3%83%88%E3%83%AC%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0)
    - [特徴量スケーリング](https://qiita.com/jyx/items/8f8bcd5ec5facf6b3afb#%E7%89%B9%E5%BE%B4%E9%87%8F%E3%82%B9%E3%82%B1%E3%83%BC%E3%83%AA%E3%83%B3%E3%82%B0)
    - [カテゴリ/テキストの特徴量の処理](https://qiita.com/jyx/items/8f8bcd5ec5facf6b3afb#%E3%82%AB%E3%83%86%E3%82%B4%E3%83%AA%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%81%AE%E7%89%B9%E5%BE%B4%E9%87%8F%E3%81%AE%E5%87%A6%E7%90%86)


## テスト(検証)

モデルが既に生成されている場合にまず確認すべきは以下についてです。

- 交差検証
- 学習曲線

#### 交差検証

モデルの性能検証方法にはいくつかあります。**ホールドアウト検証**と呼ばれる方法は全データセットを訓練データとテストデータに2分割(7:3, 6:4など)して片方のデータで訓練したモデルを残った方でテストするというものです。
ですがこの手法だと訓練、ハイパーパラメータの調整を単一のデータに対して行ってしまうことになるため未知のデータに対する汎化性能への疑問が残ります。

そこでより信頼できる検証方法として利用したいのが交差検証です。
交差検証でもまずホールドアウトと同様に訓練データとテストデータに分割します。そこから下記画像のように訓練データをk個に分割し、分割したうちの1つ(検証用データ)を除いたデータで訓練するということを検証用データを切り替えながらk回行います。
そして検証用データで十分な性能が出たら、最初に確保しておいたテストデータを使って未知のデータに対する性能を確認します。複数パターンの検証データを用いて性能の検証を行うため、ホールドアウトに比べてテスト結果がより信頼できるものになります。

プロダクションレベルでもホールドアウトでテストしたのみで「やったー！」となってしまっている例はこれまで何度か見ているので、この点は意外と見落とされがちな印象です。

![K-fold_cross_validation_EN.jpg](https://qiita-image-store.s3.amazonaws.com/0/293831/49e78a4f-d005-0735-883d-2aa021c6dedf.jpeg)
([Wikipedia](https://en.wikipedia.org/wiki/Cross-validation_(statistics))より)


#### 学習曲線

生成したモデルが過学習しているかどうか判断がつかず悶々とするというのはなんとも精神衛生上よくないものです。その検証と、次に取るべきアクションを決めるために有効なのが学習曲線の利用です。

学習曲線は横軸に訓練データの量、縦軸に性能スコアをとる二次元グラフで表され、訓練データに対する性能と検証データに対する性能をプロットすることでモデルの状態を直感的に理解することが可能になります。以下がその例です。青の曲線が訓練データに対する性能、ピンクの曲線が検証データに対する性能を示しています。

<img width=70% alt="スクリーンショット 2018-09-25 6.03.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/293831/cc05b5aa-ac3e-309a-6821-9a90870b17c5.png">
([Coursera Machine Learning course](https://www.coursera.org/learn/machine-learning)より)

これは高バイアスと呼ばれる状態で、データに対してモデルが適合しきれていない(underfitting)状態を示しています。訓練データを増やすことで検証データに対する性能はある程度の水準までは上がっていますが、そこからはほぼ横ばいとなり十分な性能を示していません。この場合に取りうる方針としては

- より強力なアルゴリズムを利用する
- 正則化の制約を緩める

などがあります。

<img width=70% alt="スクリーンショット 2018-09-25 6.03.07.png" src="https://qiita-image-store.s3.amazonaws.com/0/293831/c84e4cdb-8bf7-3304-0a73-40b55e339e66.png" >
([Coursera Machine Learning course](https://www.coursera.org/learn/machine-learning)より)


そしてこちらは高バリアンスと呼ばれる状態で、モデルが過学習(overfitting)の状態であることを示しています。
訓練データを増やしても、訓練データに対する性能と検証データに対する性能に大きな隔たりがあり、既に知っているデータに対してはよく適合していても未知のデータに対してはうまく適合できていない(汎化性能が低い)ことを示しています。この場合に取りうる方針は

- 訓練データを増やす
- 特徴量を減らす
- 正則化の制約を強める

などがあります。

学習曲線からは上記のように現状と今後取るべき方針を知ることができるので何をすべきか迷ったらまず出力してみるのが良いでしょう。

## データセット

- 特徴量の選定
- サンプリングバイアス
- データ量

#### 特徴量の選定

ある程度直感的に理解可能なことではありますが、推論したい属性と相関の弱い属性を特徴量に加えて訓練を行ってもモデルの性能向上には役立ちません。このため訓練の前にどの特徴量を説明変数に加えるかを慎重に選ぶ必要があります。また、**次元の呪い**とも言われますが、一般に扱うデータの次元数が増えると、それに伴って必要な訓練データの数も指数関数的に増加していくことが知られています。選定の際に使われる主な手法は以下のものです。

- [特徴選択](http://ibisforest.org/index.php?%E7%89%B9%E5%BE%B4%E9%81%B8%E6%8A%9E)
- 特徴の結合による特徴作成(feature creation)

またランダムフォレストなどの手法では各特徴量の相対的な重要度を容易に知ることが可能です。scikit-learnにはそのためのAPIがあります。

- [Feature importances with forests of trees](http://scikit-learn.org/stable/auto_examples/ensemble/plot_forest_importances.html)

#### サンプリングバイアス

用意した訓練データがこれから推測したい未知のデータをよく代表したものかどうかをチェックする必要があります。例えば、大人から子供まで年齢別の疾患リスクを推論したいのに訓練データが若者のデータのみに偏っていては良いモデルは作れません。

#### データ量

現在のアルゴリズム、特徴量に対して十分な量のデータが用意できているかどうかを検証します。学習曲線を利用して、バイアス/バリアンスを調べることで行いますが、詳しくは学習曲線の項で説明しています。

## トレーニング

- 特徴量スケーリング
- カテゴリ/テキストの特徴量の処理

#### 特徴量スケーリング

特徴量は測定単位の取り方によって訓練結果に与える影響が大きく異なってしまいます。高さを表す特徴量Aと幅を表す特徴量BがあるとしてAについてはメートル、Bについてはナノメートル(10億分の1メートル)を単位に取るとそれだけでBが訓練結果に与える影響はAの10億分の1になってしまうわけです。こういったことを防ぐためにそれぞれの特徴量を同じ範囲にスケーリングする必要があります。

#### カテゴリ/テキストの特徴量の処理

一般に特徴量はカテゴリ/テキストのような形より数値として扱える方が操作しやすいので変換するのがベターなのですが、素直に数値に変換してしまうと思わぬ影響が出ます。ユーザの購入品種(日用品、家電、書籍、食品とします)という特徴量があったとして、素直に数値変換すると

0. 日用品
1. 家電
2. 書籍
3. 食品

となるわけですが、この変換だと機械学習アルゴリズムが数値的に近いカテゴリを意味的にも近いものであると勘違いする(本来は存在しないパターンを見出す)問題が発生します。日用品(1)は食品(4)よりも家電(2)により近いといったようにです（もちろん実際にはそんな意味はない)。
このような事態を避けるために利用されるのが、ワンホットエンコーディングと呼ばれる手法です。カテゴリが日用品ならある特徴量を1に、そうでなければ0にする。家電であるなら別の特徴量を1にするといった形です。

例1: 日用品の場合

| is_日用品 | is_家電 | is_書籍 | is_食品 |
|:-----------:|:------------:|:------------:|:------------:
| 1       | 0        |  0         | 0 |

例2: 書籍の場合

| is_日用品 | is_家電 | is_書籍 | is_食品 |
|:-----------:|:------------:|:------------:|:------------:
| 0      | 0        |  1         | 0 |

以上、見落としやすい点を中心に検証項目をまとめました。モデルをブラッシュアップする際の一助となれば幸いです。