Kurs uczenia maszynowego od zera · Lekcja 2.6 · 13 z 33 gotowych lekcji · 12 min
Metryka i próg pod koszt pomyłek
W skrócie
Próg wybierasz pod ceny pomyłek, nie z przyzwyczajenia. Gdy przeoczenie kosztuje 10 razy więcej niż fałszywy alarm, najtańszy próg leży blisko 0,09, nie 0,5.
Rozgrzewka Dwa pytania z wcześniejszych lekcji. Minuta, a lekcji nie blokuje.
W lekcji 2.3 krzywe pokazały menu progów, a w lekcji 2.4 sprawdziłeś, kiedy liczby modelu są prawdziwymi procentami. Teraz wybierzesz z tego menu jeden próg. Nie z przyzwyczajenia (0,5) i nie pod ulubioną metrykę, tylko pod to, ile naprawdę kosztuje każda pomyłka.
Wybierz odpowiedź i pewność.
Odpowiedz, żeby odblokować lab.
Eksperyment
Ten interaktywny eksperyment działa w przeglądarce z włączonym JavaScriptem. Tekst wokół opisuje, co w nim widać.
Pokaż odpowiedź
Poprawna odpowiedź: Bliżej 0,1, bo alarm opłaca się już przy niewielkim ryzyku
Teoria decyzji: alarm opłaca się, gdy p · 10 > (1 − p) · 1, czyli p > 1/11 ≈ 0,09. W labie próg 0,09 kosztuje 125, a zwykłe 0,5 aż 254. Najtańszy próg na walidacji, 0,06, kosztuje 111, ale tylko na tych samych wynikach, na których go wybrano.
Spróbuj
- Zostaw ceny 10 i 1 i przesuwaj próg z 0,5 w dół. Gdzie koszt jest najniższy? Ile jest wtedy przeoczeń, a ile fałszywych alarmów?
- Ustaw oba koszty na 1. Gdzie jest teraz najtańszy próg? Porównaj go z progiem najlepszym dla F1.
- Ustaw fałszywy alarm droższy od przeoczenia. Po której stronie 0,5 ląduje najtańszy próg?
- Wróć do cen 10 i 1 i porównaj trzy koszty: najtańszego progu, uczciwego sprawdzianu i progu z teorii. Który wybór jest najtańszy na biopsjach, których nie użyto do wyboru?
Gdy już sprawdzisz to w labie, nazwijmy, co widzisz.
Pomysł w prostych słowach
Każda pomyłka ma cenę. Przeoczony guz złośliwy (FN) to choroba wykryta za późno. Fałszywy alarm (FP) to niepotrzebna biopsja i stres. Gdy znasz ceny, koszt progu to zwykła suma: przeoczenia razy cena przeoczenia plus fałszywe alarmy razy cena alarmu. Najlepszy próg to ten z najmniejszą sumą na danych walidacyjnych.
Przy cenach 10 i 1 próg 0,5 daje 24 przeoczenia i 14 fałszywych alarmów, czyli koszt 254. Najtańszy próg na walidacji to 0,06: 2 przeoczenia i 91 alarmów, koszt 111. Ta liczba jest jednak za optymistyczna, bo próg wybrano i wyceniono na tych samych wynikach (więcej w „Dlaczego to działa”). Dla porównania biopsja dla wszystkich kosztuje 357, a brak jakiejkolwiek biopsji 2120.
Jeśli model jest skalibrowany, próg da się też policzyć bez szukania. Biopsja ma prawdopodobieństwo złośliwości p. Alarm kosztuje wtedy średnio (1 − p) · 1, a brak alarmu p · 10. Alarm opłaca się, gdy p · 10 > (1 − p) · 1, czyli gdy p > 1/11 ≈ 0,09. Ogólnie próg to c_FP / (c_FP + c_FN). To wynik teorii decyzji, a nie pomiar: zakłada, że liczby modelu są prawdziwymi procentami (lekcja 2.4). Ten model jest dobrze skalibrowany (ECE 0,010). Próg 0,09 kosztuje w labie 125, mniej niż połowa kosztu progu 0,5, i nikt go nie stroił na tych danych.
Jak to policzono
- Biopsje: Breast Cancer Wisconsin (Diagnostic), UCI, licencja CC BY 4.0. 569 biopsji (212 złośliwych, 357 łagodnych), 10 pomiarów „mean” każdej.
- Wyniki z walidacji krzyżowej w 5 częściach (
StratifiedKFold(5)w scikit-learn): każdą biopsję ocenia model, który jej nie widział. - Model: standaryzacja i regresja logistyczna (C = 1). Progi od 0,01 do 0,99 co 0,01.
- Ceny pomyłek: przeoczenie 10, fałszywy alarm 1. To przykład, a nie wycena medyczna.
Dlaczego to działa
Lab i teoria prawie się zgadzają: najtańszy próg wychodzi 0,06, teoria mówi 0,09. Różnica bierze się stąd, że 569 biopsji to niedużo, a jedno przeoczenie waży tyle co 10 alarmów, więc krzywa kosztu skacze. Jej dno jest płaskie i postrzępione: próg 0,13 kosztuje tyle samo co 0,06 (111), a 0,09 kosztuje 125. Na 20 innych podziałach na części (kod niżej) najtańszy próg wypada od 0,04 do 0,13, średnio 0,08. Teoria trafia w środek tego przedziału, a lab pokazuje, jak szerokie jest dno.
Najtańszy próg ma jednak haczyk. Lab sprawdza 99 progów i wybiera ten, który na tych 569 biopsjach wypadł najlepiej, także dzięki przypadkowym trafieniom. Koszt 111 jest więc za optymistyczny: to ta sama klątwa zwycięzcy co przy strojeniu (lekcja 3.5). Uczciwy sprawdzian: wybierz próg na 4/5 biopsji i policz jego koszt na pozostałej 1/5, pięć razy. Tak wybrany próg kosztuje 141, więcej niż próg z teorii 0,09 (125), którego nikt nie stroił. Na 20 innych podziałach uczciwy koszt wybranego progu to od 106 do 153 (średnio 129), a próg z teorii kosztuje od 105 do 136 (średnio 117) i jest tańszy w 16 z 20. Wniosek: przy skalibrowanym modelu próg z teorii to mocny i tani punkt wyjścia, a strojenie progu na tych samych danych zawyża oszczędność.
Kierunek jest zawsze ten sam: im droższe przeoczenie, tym niższy próg, a im droższy fałszywy alarm, tym wyższy. Przy równych cenach najtańszy próg to 0,65 (koszt 33). Gdy alarm jest droższy od przeoczenia, najtańszy próg ląduje powyżej 0,5.
Częsty błąd
Prawda czy fałsz: „F1 to dobra metryka do wszystkiego”. Fałsz. F1 = 2·TP / (2·TP + FN + FP), więc F1 waży przeoczenie i fałszywy alarm tak samo, nawet gdy ich ceny są różne. W labie próg najlepszy dla F1 to 0,65 (F1 0,918). Przy cenach 10 i 1 kosztuje on 276: więcej niż zwykłe 0,5 (254) i prawie 2,5 raza więcej niż najtańszy próg (111). Na 20 innych podziałach próg najlepszy dla F1 kosztuje od 1,6 do 2,9 raza więcej niż najtańszy.
Nawet przy równych cenach F1 to nie to samo co koszt. W labie przy cenach 1 i 1 najtańszy próg wypada akurat tam, gdzie najlepsze F1 (0,65), ale to nie reguła. Koszt przy równych cenach to po prostu liczba pomyłek, a F1 to ułamek, w którym trafne „nie” (TN) w ogóle się nie liczą. Na 20 innych podziałach te dwa progi różnią się w 3.
Gdy znasz ceny pomyłek, licz koszt. Gdy ich nie znasz, zapytaj o nie, zanim wybierzesz metrykę: wybór metryki to też decyzja o cenach, tylko niewypowiedziana.
Quiz
Trzy pytania na sprawdzenie się. Wybierz odpowiedź albo rozwiń odpowiedź pod pytaniem. Z klawiatury: strzałki wybierają, Enter albo spacja zatwierdza.
Najważniejsze wnioski
- Próg wybierasz pod ceny pomyłek: koszt to przeoczenia razy ich cena plus fałszywe alarmy razy ich cena, liczony na walidacji.
- Dla skalibrowanego modelu teoria daje próg c_FP / (c_FP + c_FN); przy cenach 10 i 1 to około 0,09. To mocny punkt wyjścia: próg strojony na tych samych danych wygląda taniej, niż jest.
- Droższe przeoczenia obniżają próg, a droższe fałszywe alarmy go podnoszą.
- F1 waży oba błędy tak samo i pomija trafne „nie”; gdy znasz ceny, licz koszt.
Głębiej: wzór, kod, praktyka
Matematyka
Koszt progu t: K(t) = c_FN · FN(t) + c_FP · FP(t). Najtańszy próg na walidacji to t = argmin K(t). Koszt K(t) liczony na tych samych danych jest za optymistyczny; uczciwy koszt liczysz na danych, których nie użyto do wyboru t*.
Biopsja ma prawdopodobieństwo złośliwości p. Alarm kosztuje średnio (1 − p) · c_FP, a brak alarmu p · c_FN. Alarm opłaca się, gdy p · c_FN > (1 − p) · c_FP, czyli p > c_FP / (c_FP + c_FN). Dla c_FN = 10 i c_FP = 1 to 1 / 11 ≈ 0,09.
F1 = 2·TP / (2·TP + FN + FP): FN i FP mają w mianowniku tę samą wagę 1.
W kodzie (Python)
Ten sam eksperyment w scikit-learn: wyniki z walidacji krzyżowej, koszt każdego progu od 0,01 do 0,99, uczciwy koszt wybranego progu, a potem to samo na 20 innych podziałach na części.
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import StratifiedKFold, cross_val_predict
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import f1_score
X, y = load_breast_cancer(return_X_y=True)
X, y = X[:, :10], 1 - y # 10 pomiarów „mean”, jak w labie; 1 = złośliwy
model = make_pipeline(StandardScaler(), LogisticRegression())
t = np.arange(1, 100) / 100 # progi 0.01 ... 0.99, jak w labie
def costs(p, i=slice(None), c_fn=10, c_fp=1): # przeoczenie kosztuje 10, fałszywy alarm 1; i = które biopsje
return np.array([c_fn * ((p[i] < s) & (y[i] == 1)).sum() + c_fp * ((p[i] >= s) & (y[i] == 0)).sum() for s in t])
def scores(cv): # każdą biopsję ocenia model, który jej nie widział
return cross_val_predict(model, X, y, cv=cv, method="predict_proba")[:, 1]
def held_out(p, cv): # najtańszy próg wybrany na 4/5 biopsji, koszt liczony na pozostałej 1/5, pięć razy
return sum(costs(p, b)[costs(p, a).argmin()] for a, b in cv.split(X, y))
p = scores(StratifiedKFold(5))
c, f1 = costs(p), np.array([f1_score(y, p >= s) for s in t])
print(f"cheapest threshold {t[c.argmin()]:.2f} (cost {c.min()}); theory 1/11 = {1 / 11:.2f} (cost {c[8]}); 0.5 costs {c[49]}; best F1 at {t[f1.argmax()]:.2f} costs {c[f1.argmax()]}")
print(f"picked on 4/5, priced on the other 1/5: {held_out(p, StratifiedKFold(5))}; theory 1/11: {c[8]}")
r = []
for s in range(20): # 20 innych podziałów na 5 części
cv = StratifiedKFold(5, shuffle=True, random_state=s)
q = scores(cv)
cq, fq = costs(q), np.array([f1_score(y, q >= u) for u in t])
r.append((t[cq.argmin()], cq[fq.argmax()] / cq.min(), cq[49] / cq.min(), held_out(q, cv), cq[8], costs(q, c_fn=1).argmin() != fq.argmax()))
r = np.array(r)
print(f"20 other cuts: cheapest threshold {r[:, 0].min():.2f} to {r[:, 0].max():.2f} (mean {r[:, 0].mean():.2f}); best F1 costs {r[:, 1].min():.1f} to {r[:, 1].max():.1f} times the cheapest, 0.5 costs {r[:, 2].min():.1f} to {r[:, 2].max():.1f} times")
print(f"20 other cuts, held out: the picked threshold costs {r[:, 3].min():.0f} to {r[:, 3].max():.0f} (mean {r[:, 3].mean():.0f}), theory 1/11 costs {r[:, 4].min():.0f} to {r[:, 4].max():.0f} (mean {r[:, 4].mean():.0f}); theory is cheaper in {(r[:, 4] < r[:, 3]).sum():.0f} of 20; at equal prices the cheapest and the best-F1 threshold differ in {r[:, 5].sum():.0f} of 20")
Wynik
cheapest threshold 0.06 (cost 111); theory 1/11 = 0.09 (cost 125); 0.5 costs 254; best F1 at 0.65 costs 276
picked on 4/5, priced on the other 1/5: 141; theory 1/11: 125
20 other cuts: cheapest threshold 0.04 to 0.13 (mean 0.08); best F1 costs 1.6 to 2.9 times the cheapest, 0.5 costs 2.0 to 2.5 times
20 other cuts, held out: the picked threshold costs 106 to 153 (mean 129), theory 1/11 costs 105 to 136 (mean 117); theory is cheaper in 16 of 20; at equal prices the cheapest and the best-F1 threshold differ in 3 of 20
Przy podziale StratifiedKFold(5) liczby są takie same jak w labie: najtańszy próg 0,06 (koszt 111), teoria 0,09 (125), próg 0,5 kosztuje 254, a próg najlepszy dla F1 276. Na 20 innych podziałach najtańszy próg wypada od 0,04 do 0,13, średnio 0,08, a zwykłe 0,5 kosztuje od 2,0 do 2,5 raza więcej niż najtańszy. Próg wybrany na 4/5 biopsji i wyceniony na pozostałej 1/5 kosztuje 141, tak jak w labie. Na 20 innych podziałach taki wybór kosztuje od 106 do 153 (średnio 129), próg z teorii od 105 do 136 (średnio 117) i jest tańszy w 16 z 20. Przy równych cenach najtańszy próg i próg najlepszy dla F1 różnią się w 3 z 20 podziałów.
Pobierz notebook (.ipynb). Otwórz go w Jupyterze albo wgraj do Google Colab; brakujące dane pobierze sam.
Dla praktyka
- Ceny pomyłek ustal z ludźmi, którzy ponoszą ich skutki (lekarz, dział ryzyka), zanim zobaczysz wyniki modelu. Inaczej łatwo dobrać ceny pod próg, który już ci się podoba.
- W scikit-learn próg pod koszt dobiera
TunedThresholdClassifierCVz własnymscoring(np. przezmake_scorer). Sam próg stosujesz tak:predict_proba(X)[:, 1] >= t. - Próg dobieraj na walidacji, a jego koszt sprawdzaj na danych, których nie użyłeś do wyboru (test albo odłożona część, jak w labie). Koszt podawaj obok dwóch prostych punktów odniesienia: „wszyscy na biopsję” i „nikt”.
- Wzór c_FP / (c_FP + c_FN) stosuj tylko do skalibrowanego modelu (lekcja 2.4). Gdy model jest przesadnie pewny, szukaj progu na krzywej kosztu.
Czy to było pomocne?
Dzięki! To pomaga nam poprawiać Atlas.
Więcej w Atlasie
Hasła encyklopedii o pojęciach z tej lekcji: