クリーム色の背景、色付き表示、高コントラスト、大きな文字のほうが読みやすいですか?配色と文字を選ぶと、すべてのページに一度で反映されます。

無料レッスン

分類器を正直に評価する

このレッスンのあとで: 正解率だけでなく、混同行列、適合率、再現率で、分類器を評価できる。

60分のレッスンコマンド2件JupyterLab データサイエンスラボ:pandas、Matplotlib、scikit-learn をブラウザーで

96パーセントなのに、役に立たない

迷惑メールのフィルターを、1000通で試します。960通で当たったので、96パーセントです。チームは喜びます。

ところが、このフィルターは、どのメールにも「迷惑メールではない」と答えていました。1000通のうち40通は迷惑メールでした。1つの点数が、誤りを丸ごと隠していたのです。

このレッスンのゴール

メモ

正解率だけでなく、混同行列、適合率、再現率で、分類器を評価できる。

キーワード

ことばいみ
正解率すべてのメールのうち、モデルが正しく分けた割合
偏った表片方のラベルが、もう片方よりずっと多い表
混同行列ラベルごとの正しい答えと誤った答えを数えた表
適合率迷惑メールと判定したもののうち、本当にそうだった割合
再現率本物の迷惑メールのうち、見つけた割合
しきい値この点数以上を迷惑メールと判定する、境目の点数

学生が入力するセルは、このプレビューでは空白です。

正解率は、2種類の間違いを1つにする

正解率は、正しい答えをすべて同じに数えます。ラベルが同じくらいの数なら、それで十分です。

表が偏っていると、通用しません。1000通のうち40通が迷惑メールなら、いつも「迷惑メールではない」と答えるモデルは960回当たります。96パーセント当たり、迷惑メールは1通も見つけません。

いつも「ちがう」と答えるモデルを採点する

コマンド
docker exec jupyter python3 -c "t=[1]*40+[0]*960; g=[0]*1000; print(sum(a==b for a,b in zip(t,g))/1000)"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

答えを4種類に数える

探しているものは迷惑メールなので、それを「陽性」と呼びます。どのメールも、4つの箱のどれかに入ります。

見つけた: 迷惑メールで、判定した。誤検知: 迷惑メールではないのに、判定した。見逃し: 迷惑メールなのに、判定しなかった。正しく通した: 迷惑メールではなく、判定しなかった。4つの数をまとめたものが、混同行列です。

例: 1000通でのフィルター

迷惑メールと判定判定しなかった
本当に迷惑メール (40)見つけた: 30見逃し: 10
迷惑メールではない (960)誤検知: 20正しく通した: 940

学生が入力するセルは、このプレビューでは空白です。

行列、適合率、再現率を表示する

コマンド
docker exec jupyter python3 -c "from sklearn.metrics import confusion_matrix, precision_score, recall_score; t=[1]*40+[0]*960; g=[1]*30+[0]*10+[1]*20+[0]*940; print(confusion_matrix(t,g)); print(round(precision_score(t,g),3), round(recall_score(t,g),3), (30+940)/1000)"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

適合率と再現率は、別の問い

適合率は問います。フィルターが迷惑メールと言ったとき、どれくらい合っているか。ここでは、判定した50通のうち30通で、0.6です。

再現率は問います。本物の迷惑メールの、どれだけを見つけたか。ここでは40通のうち30通で、0.75です。正解率は 0.97 でした。いつも「ちがう」と答えるものよりよいのですが、正解率では、その差がほとんど見えません。

しきい値を動かすと、一方が増える

多くのモデルは点数を出し、しきい値がそれをラベルに変えます。しきい値を下げると、判定されるメールが増えます。迷惑メールは多く見つかりますが、普通のメールも多く判定されます。

つまり適合率と再現率は引き合い、人が選ばなければなりません。コードを Run して、数が動くのを見ましょう。

10通で、4つのしきい値

コード: python
# 10通のメール: モデルが付けた点数 (0 から 1) と、本当に迷惑メールだったか。
messages = [
    (0.95, 1), (0.9, 1), (0.8, 0), (0.7, 1), (0.6, 0),
    (0.5, 1), (0.4, 0), (0.3, 0), (0.2, 0), (0.1, 0),
]
for limit in [0.9, 0.7, 0.5, 0.3]:
    caught = 0
    false_alarms = 0
    missed = 0
    for pair in messages:
        score = pair[0]
        spam = pair[1]
        flagged = score >= limit
        if flagged and spam == 1:
            caught = caught + 1
        if flagged and spam == 0:
            false_alarms = false_alarms + 1
        if not flagged and spam == 1:
            missed = missed + 1
    print("しきい値", limit, "見つけた", caught, "誤検知", false_alarms, "見逃し", missed)
# 受信箱なら、どのしきい値にしますか。銀行なら、どうでしょう。

例: しきい値ごとの結果

しきい値見つけた誤検知見逃し適合率再現率
0.92021.00.5
0.73110.750.75
0.54200.6671.0
0.34400.51.0

学生が入力するセルは、このプレビューでは空白です。

よくある間違い

注意

1つの数がいちばんよいしきい値が、最良だと思う人が多いです。費用を知らなければ、最良のしきい値はありません。受信箱は、少しの迷惑メールとは暮らせます。不正検知は、1件も通せません。

さらに: 間違いの費用

見逃しは読む手間が1分、誤検知は失くしたメールを探す手間が5分かかるとします。4つのしきい値の表を使います。

しきい値ごとに、失う分数を計算します。いちばん安いのはどれですか。誤検知が1分だけなら、変わりますか。

このラボとソースについて: JupyterLab データサイエンスラボ:pandas、Matplotlib、scikit-learn をブラウザーで

授業で使いますか?このモジュールを学生に割り当てると、教員用ガイド、自動採点つきの課題、学生ごとのラボを使えます。