ROC曲線とAUCについて定義と関係性をまとめたよ

### はじめに
[こちらの記事](http://www.randpy.tokyo/entry/roc_auc)の内容を１枚絵にまとめたものになります。以下、文章で少しだけ補足します。
![edit.jpg](https://qiita-image-store.s3.amazonaws.com/0/56466/7a549820-496c-db49-faa8-5f73106760b0.jpeg)

#### 正解率系の各種指標について
(参考)[こちらの記事](http://www.randpy.tokyo/entry/roc_auc)より引用させて頂きました。
![roc_auc.jpg](https://qiita-image-store.s3.amazonaws.com/0/56466/ad750690-a4a7-3081-4dad-6f6fdeb7d861.jpeg)

クラス分類モデルの性能評価には様々な評価指標が存在しますが、上記の各種指標の計算で諸々算出されます。
用語を覚える際に混乱してしまいがちですが、以下の関係性さえ理解しておけば丸暗記しなくても思い出せます。

__前一文字:正解か不正解かを示す -> T or F__
__後一文字:モデルからの予測分類を示す -> P or N__


偽陽性は、FP(間違って陽性判定した数) / FP + TN(陰性全体の母数)

真陽性は、TP(正しく陽性判定した数) / TP + FN(陽性全体の母数)

#### テキストでROC曲線とAUCをまとめる
![roc_intro3 (1).png](https://qiita-image-store.s3.amazonaws.com/0/56466/bebfc8ac-744a-7203-5450-d8d1f7553e7e.png)

__①ROC曲線ってなんだ?__
クラス分類するためのスコア閾値を外部の変数として変化させ、偽陽性率を横軸に、真陽性率を縦軸にプロットしたものがROC曲線に当たります。'偽陽性率が0%の状態(⇨陽性への判定閾値が限りなく高い)で、真陽性率が高いモデル'が予測率の高いモデルと言えます。

__②グラフをどう解釈する?__
"スコアが0.999999以上のみを陽性と見なすよ！"という厳しい条件においても、陽性を正しく検出できるモデルは優れたモデルと言えますよね。偽陽性率(横軸)が０の状態というのは、まさに上記のような条件を再現したものだと言えます。(実際にクラス判定の閾値がいくらに設定されているかは、入力によって異なるので、あくまで例です。)

__③どんなグラフになる?__
そして、偽陽性率が高まる = (判定閾値が低くなり)陽性判定が増える = 真陽性は増えるという関係が常に成り立つので、ROC曲線は必ず右上がりになります。

__④AUCはこういうもの__
っで、あれば、初期の陽性率の立ち上がりが急カーブを描いている、曲線と横軸との間の面積が大きいモデルというのは、'偽陽性率が低い、陽性判定の閾値が高く、条件が厳しい段階から正しく分類できていたモデル'となるわけですから、__AUC(ROC曲線の横軸と縦軸に囲まれた部分の面積)__は分類モデルのパフォーマンス評価指標として有用なわけです。

### Scikit-learnでAUCを計算する
roc_auc_score()に、正解ラベルと予測スコアを渡すとAUCを計算してくれます。
楽チンです。

```python:auc.py
import numpy as np
from sklearn.metrics import roc_auc_score
y = np.array([0, 0, 1, 1])
pred = np.array([0.1, 0.4, 0.35, 0.8])
roc_auc_score(y, pred)
```
クラス分類問題の精度評価指標はいくつかありますが、案件に応じて最適なものを使い分けていましょう。

### 正解率とAUCを計算して最適なモデルを選択するスクリプト
かなり冗長だが、学習過程で作ったコードを貼ってみました。

``` python:model_selection.py
# import basice apis
import numpy as np
import pandas as pd
%matplotlib inline  
from sklearn.datasets import load_breast_cancer
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.pipeline import Pipeline
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score  
from sklearn.metrics import roc_auc_score
import pickle

# import Sample Data to learn models
dataset = load_breast_cancer()
X = pd.DataFrame(dataset.data, columns=dataset.feature_names)
y = pd.DataFrame(dataset.target, columns=['y'])

# cross-validation by holdout
X_train,X_test,y_train,y_test = train_test_split(X,
                                                 y,
                                                 test_size=0.20,
                                                 random_state=1)
# set pipelines for two different algorithms
pretrained_pipes = []
trained_pipes = []
pipe_knn = Pipeline([('scl',StandardScaler()),('est',KNeighborsClassifier())])
pipe_logistic = Pipeline([('scl',StandardScaler()),('est',LogisticRegression())])
pipe_gbc = Pipeline([('scl',StandardScaler()),('est',GradientBoostingClassifier())])

pretrained_pipes.append(pipe_knn)
pretrained_pipes.append(pipe_logistic)
pretrained_pipes.append(pipe_gbc)

# パイプラインの学習
for pipeline in pretrained_pipes:
    trained_pipe = pipeline.fit(X_train,y_train.as_matrix().ravel())
    trained_pipes.append(trained_pipe)
    
# パイプラインの評価（評価は指定指標の下で実施されるようにすること）
# 結果格納データフレーム生成用に各種配列を作成
result_clumns = ['name','accurate_rate','roc']
result_names = ['KNN','LOGISTIC','GBC']
result_accuracy = []
result_roc = []

# 各モデルで性能評価する
for pipeline in trained_pipes:
    result_accuracy.append(accuracy_score(y_test,pipeline.predict(X_test)))
    result_roc.append(roc_auc_score(y_test,pipeline.predict(X_test)))

# 　リスト->ディクショナリ->データフレームに変換
values = [result_names,result_accuracy,result_roc]
result_dataframe = pd.DataFrame(dict(zip(result_clumns,values))).loc[:,['name','accurate_rate','roc']]
high_accurate_model = result_dataframe.sort_values(by=["accurate_rate"], ascending=False).iloc[0,[0]].values[0]
high_accurate_score = result_dataframe.sort_values(by=["accurate_rate"], ascending=False).iloc[0,[1]].values[0]
high_roc_model = result_dataframe.sort_values(by=["roc"], ascending=False).iloc[0,[0]].values[0]
high_roc_score = result_dataframe.sort_values(by=["roc"], ascending=False).iloc[0,[2]].values[0]

result_dataframe

#結果呼び出し用関数
def model_selection(test_score):
    if test_score == 'accurate':
        print('最も正解率が高かったのは',high_accurate_model,'で、その値は',round(high_accurate_score,4),'でした')
    elif test_score == 'auc':
        print('最もAUCが高かったのは',high_roc_model,'で、その値は',round(high_roc_score,4),'でした')
        result_dataframe
    else:
        print('エラー！model_selection関数には、auc か accurateを引数として渡してください。')

#　関数呼び出し
model_selection('accurate')
model_selection('auc')
model_selection('hogehoge')

>最も正解率が高かったのは LOGISTIC で、その値は 0.9825 でした
>最もROCが高かったのは LOGISTIC で、その値は 0.9762 でした
>エラー！model_selection関数には、auc か accurateを引数として渡してください。
```