基本トピック
ROC曲線
PR曲線
AUC(Area Under the Curve)
実行例に基づくROC-AUCとPR-AUCの特徴の確認
実行例①
[1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
上記の順にスコアリングが得られた場合、上記をsample_AUC_1.csv
(20行)に保存します。このとき下記を実行することでROC曲線とPR-曲線の描画を行うことができます。
import numpy as np
import pandas as pd
from sklearn import metrics
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme()
y = pd.read_csv("sample_AUC_1.csv", header=None)
scores = np.linspace(1, 0, y.shape[0])
fpr, tpr, thresholds = metrics.roc_curve(y, scores)
precision, recall, thresholds = metrics.precision_recall_curve(y, scores)
roc_auc = metrics.auc(fpr, tpr)
pr_auc = metrics.auc(recall, precision)
fig, axs = plt.subplots(1, 2, figsize=(12, 5))
axs[0].plot(fpr, tpr)
axs[0].set_title("ROC-Curve(AUC: {:.3f})".format(roc_auc))
axs[0].set_xlabel("fpr(false positive rate)")
axs[0].set_ylabel("tpr(true positive rate)")
axs[1].plot(recall, precision)
axs[1].set_title("PR-Curve(AUC: {:.3f})".format(pr_auc))
axs[1].set_xlabel("recall")
axs[1].set_ylabel("precision")
plt.savefig("AUC_1.png")
実行結果よりROC曲線が右上がり、PR曲線が右下がりの曲線となることが確認できます。
実行例②
実行例①ではROC-AUCとPR-AUCのどちらも1に近い値が得られました。以下ではROC-AUCが高い一方でPR-AUCが低い例について確認します。
[0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
上記をsample_AUC_2.csv
(100行)に保存し、前項(実行例①)と同じスクリプトをファイル名のみ変えて実行すると下記のような結果が得られます。
上図より、PR-AUC(Precision Recall Area Under the Curve)は上位のサンプルのスコアに全体の値が大きく左右される指標であることが確認できます。PR-AUCは「陽性のサンプルの大半が出てrecallが1に近づくまでprecisionが大きくなってはならない」という指標であるので、異常検知のように陽性と陰性のサンプルの数が大きく異なるような場合に厳格な評価を下す指標であるといえます。
このようにTPR(True Positive Rate)とFPR(False Positive Rate)を元に作成するROC曲線は「陽性と判定したサンプル」に着目してプロットを行った曲線です。一方で、下記のようなスクリプトを実行することで「陰性と判定したサンプル」に着目してプロットを作成できます。
import numpy as np
import pandas as pd
from sklearn import metrics
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme()
y1 = pd.read_csv("sample_AUC_2.csv", header=None)
y2 = 1-y1
scores1 = np.linspace(1, 0, y1.shape[0])
scores2 = 1-scores1
fpr, tpr, thresholds1 = metrics.roc_curve(y1, scores1)
fnr, tnr, thresholds2 = metrics.roc_curve(y2, scores2)
roc_auc = metrics.auc(fpr, tpr)
tnr_fnr_auc = metrics.auc(fnr, tnr)
fig, axs = plt.subplots(1, 2, figsize=(12, 5))
axs[0].plot(fpr, tpr)
axs[0].set_title("ROC-Curve(AUC: {:.3f}, DESC)".format(roc_auc))
axs[0].set_xlabel("fpr(false positive rate)")
axs[0].set_ylabel("tpr(true positive rate)")
axs[1].plot(fnr, tnr)
axs[1].set_title("TNR-FNR-Curve(AUC: {:.3f}, ASC)".format(tnr_fnr_auc))
axs[1].set_xlabel("fnr(false negative rate)")
axs[1].set_ylabel("tnr(true negative rate)")
plt.savefig("tnr-fnr_2.png")
上図ではスコアの昇順(ROC曲線ではスコアの降順を使用)にサンプルを確認した際のTNR(True Negative Rate)とFNR(False Negative Rate)のプロットを行いました。左と右の図が$y=-x+1$に対し線対称でありAUCが一致することは抑えておくと良いと思います。