※以下を読み込んでおいてください。
import numpy as np
from matplotlib import pyplot as plt
from scipy import stats
from sklearn.metrics import (PrecisionRecallDisplay, RocCurveDisplay,
average_precision_score, precision_recall_curve)
クイズです!第1問!
データ数が1万件の二値分類で、真値の前半5000件が陰性、後半5000件が陽性とします。
num_total = 10000
num_one = 5000
y_true = [0] * (num_total - num_one) + [1] * num_one
予測値は[0,1]のランダムな連続値の予測とします。
y_pred = np.random.uniform(low=0.0, high=1.0, size=(num_total,))
このとき、ROC曲線はどうなるでしょうか?
def show_roc_curve(y_true, y_pred):
RocCurveDisplay.from_predictions(
y_true,
y_pred,
color="darkorange",
)
plt.plot([0, 1], [0, 1], "k--", label="chance level (AUC = 0.5)")
plt.axis("square")
plt.xlabel("False Positive Rate")
plt.ylabel("True Positive Rate")
plt.title("ROC Curve")
plt.legend()
plt.show()
では、PR(Precision-Recall)曲線はどうなるでしょうか?
def show_pr_curve(y_true, y_pred):
precision, recall, thresholds = precision_recall_curve(y_true, y_pred)
average_precision = average_precision_score(y_true, y_pred, average="micro")
display = PrecisionRecallDisplay(
recall=recall,
precision=precision,
average_precision=average_precision
)
display.plot(color="darkorange")
_ = display.ax_.set_ylim([-0.05, 1.05])
display.ax_.legend(loc="best")
display.ax_.set_title("PR Curve")
plt.show()
答え

しきい値を1.0にすると全部陰性と予測するので定義的にPrecisionは1.0。しきい値を下げ始めると、ランダム予測なのでPrecisionは下がります。ランダム予測なので、陽性予測の数が少ないうちはばらつきが大きく、Precisionがかなり小さくなる場合もあります。さらにしきい値を下げていくと、ランダム予測なので、Precisionは全体の陽性の割合に近づいていきます。今は陽性の割合は50%なので、ランダムに予測すれば予測したうちの50%が正解になるはずです。
二値分類の予測は0と1が排他的なので、しきい値を下げていけばRecallは増加します。したがって、Recallは1.0に近づきつつ、Precisionは0.5を保つような曲線になります。
RP-AUCは(ほぼ)0.5になります。
では第2問!
データ数が1万件の二値分類で、真値の前半9000件が陰性、後半1000件が陽性とします。予測値は[0,1]のランダムな連続値の予測とします。
num_total = 10000
num_one = 5000
y_true = [0] * (num_total - num_one) + [1] * num_one
y_pred = np.random.uniform(low=0.0, high=1.0, size=(num_total,))
先程の問題を踏まえて、ROC曲線とPR曲線がどんな形状になるか考えてください。
では第3問!
データ数が1万件の二値分類で、真値の前半5000件が陰性、後半5000件が陽性とします。
予測値は[0,1]のランダムな連続値の予測としますが、確率密度関数はベータ分布$B(2, 5.1)$とします。y_pred
は0.5より大きい値の割合が約10%になります。
num_total = 10000
num_one = 5000
y_true = [0] * (num_total - num_one) + [1] * num_one
y_pred = stats.beta.rvs(a=2,b=5.1,size=(num_total,))
(y_pred>0.5).sum()
# 1005
ROC曲線とPR曲線がどんな形状になるか考えてください。
では第4問!
データ数が1万件の二値分類で、真値の前半9990件が陰性、後半10件が陽性とします。
予測値は最後尾のみ1の予測とします。
num_total = 10000
num_one = 10
y_true = [0] * (num_total - num_one) + [1] * num_one
pos = 1
y_pred = [0] * (num_total - pos) + [1] * pos
ROC曲線とPR曲線がどんな形状になるか考えてください。
では第5問!
データ数が1万件の二値分類で、真値の前半9990件が陰性、後半10件が陽性とします。
予測値は最後尾から20件を陽性の予測とします。
num_total = 10000
num_one = 10
y_true = [0] * (num_total - num_one) + [1] * num_one
pos = 20
y_pred = [0] * (num_total - pos) + [1] * pos
ROC曲線とPR曲線がどんな形状になるか考えてください。
では第6問!
データ数が1万件の二値分類で、真値の前半9990件が陰性、後半10件が陽性とします。
予測値は先頭から100件と、最後尾から10件を陽性の予測とします。
num_total = 10000
num_one = 10
y_true = [0] * (num_total - num_one) + [1] * num_one
y_pred = [1]*100 + [0]*(num_total-110) + [1]*10
ROC曲線とPR曲線がどんな形状になるか考えてください。
では第7問!最終問題です!
データ数が1万件の二値分類で、真値の前半9990件が陰性、後半10件が陽性とします。
予測値は先頭から9990件が陽性、最後尾から10件を陰性の予測とします。
つまり予測を全て外しています。
num_total = 10000
num_one = 10
y_true = [0] * (num_total - num_one) + [1] * num_one
pos = 10
y_pred = [1] * (num_total - pos) + [0] * pos
ROC曲線とPR曲線がどんな形状になるか考えてください。
おわりに
いかがでしたか?皆さんは何問正解できましたか?
また、正例・負例に偏りがあるときの評価指標として、ROCとPRが適切かどうか理解できましたか?
不均衡データとの向き合い方は下記も参考になります。