Precision, recall i F1 – miary oceny klasyfikatora

Tutorial o tym, jak mierzyć jakość klasyfikatora i dlaczego zwykła dokładność (ang. accuracy) to często za mało. Wyjaśniam intuicję i na przykładach pokazuję o co chodzi w: precision, recall oraz F1

Wpis jest częścią serii o mierzeniu jakości klasyfikacji, dotychczas powstały:

  1. Precision, recall i F1 – miary oceny klasyfikatora
  2. Krzywa Precision-Recall jak ją wykreślić i zinterpretować
  3. Krzywa ROC (todo)

Accuracy – czemu mnie okłamujesz?

Dokładność jest najpowszechniejszą metryką do oceny jakości klasyfikacji. Jest prosta w zrozumieniu i interpretacji. Niestety, w wielu wypadkach niewystarczającą. Gdy rozkład elementów w klasach jest nierównomierny, to posługiwanie się tylko dokładnością zaburza pogląd sytuacji.

W wielu życiowych przykładach nierównomierny rozkład jest na porządku dziennym np. rozpoznawanie chorób (zazwyczaj mamy więcej pacjentów zdrowych), klasyfikacja fraudów, rozpoznawanie błędów, rozpoznawanie named entity (NER) w tekście itp.

Przyjrzyjmy się przykładowi. Załóżmy, że w klasie „pozytywnej” mamy 990 egzemplarzy a w „negatywnej” tylko 10. Wyobraźmy sobie sytuację (nie taką rzadką), że nasz klasyfikator wyuczy się tylko rozpoznawania klasy „pozytywnej”. Każdy obiekt będzie przypisywał właśnie do niej. Policzmy dokładność (accuracy):

Dokładność wyniesie: 990/(990+10) = 0,99
990 poprawnie rozpoznanych egzemplarzy (tych „pozytywnych”) do liczby wszystkich elementów w zbiorze. Czyli całkiem nieźle, prawda?

Chyba czujecie, że jednak nie do końca. Co, jeżeli te 10 przypadków to małe, słodkie kotki, które są zagrożone wyginięciem i to właśnie je chcemy rozpoznawać i ratować?

Klasyfikator rozpoznający małe koty
Klasyfikator ratujący kotki. Photo by Jari Hytönen on Unsplash


Dobrze by było mieć metrykę, która bierze pod uwagę także, w jakim stopniu dane klasy są rozpoznawane oraz jaka jest jakość rozpoznania w obrębie danej klasy.

Jakość rozpoznania w obrębie klasy decyzyjnej

W naszym przykładzie klasa „pozytywna” rozpoznawana jest w 100% ( 990/990). Wszystkie egzemplarze pozytywne zostały rozpoznane jako pozytywne (bo wszystko rozpoznaje jako pozytywne). Jakość rozpoznania klasy pozytywnej wynosi 990/1000=0,99. Rozpoznał 1000 jako „pozytywne” z czego tylko 990 rzeczywiście przynależy do tej klasy. Ogólnie całkiem nieźle.

Sprawa wygląda zupełnie inaczej gdy popatrzymy na klasę „negatywną”. Policzmy na ile jest rozpoznawana: 0/10=0. Żaden element z 10 z klasy „negatywnej” nie został rozpoznany, uuu słabo. To może policzmy jakość rozpoznania 0/0. Klasyfikator nie rozpoznał żadnego elementu z klasy negatywnej (0 w liczniku). Nie przydzielił także żadnego elementu do tej klasy (0 w mianowniku). Jeszcze słabiej 🙁

Precission, recall, true positive, false negative i inne niezapadające w pamięć nazwy

Spróbujmy sformalizować powyższe spostrzeżenia i intuicje i na moment skupmy się tylko na klasyfikacji binarnej. W powyższym akapicie wyróżniliśmy dwie cechy dobrego klasyfikatora. Dokładność rozpoznania w obrębie klasy oraz to, w jakim stopniu rozpoznaje („chwyta”) wszystkie elementy klasy.

Przyjmijmy, że nasz klasyfikator binarny ma do rozpoznania dwie klasy „A” i „B”. I przyjmijmy do interpretacji, że klasa „A” to klasa pozytywna, a „B” negatywna (jest to tylko kwestia interpretacji i zależna od rzeczywistego przykładu). Dokonując predykcji możliwe są następujące warianty:

  1. część elementów z klasy A rozpozna jako A – poprawna klasyfikacja,
  2. część elementów z klasy A rozpozna jako B – błąd klasyfikacji,
  3. część elementów z klasy B rozpozna jako A – błąd klasyfikacji,
  4. część elementów z klasy B rozpozna jako B – poprawna klasyfikacja.

Liczbę elementów z powyższego przykładu można ładnie zestawić w tabeli (zwanej Confusion matrix). Statystycy nazwali powyższe sytuacje jako: True positive, False negative, False positive,, True negative. I skoro klasa A u nas jest pozytywna, a B negatywna można to sobie przetłumaczyć następująco: True A (wariant 1) , False B (wariant 2), False A (wariant 3), True B (wariant 4).

Confusion matrix, tabela błędów klasyfikatora
Confusion matrix, tabela skuteczności klasyfikatora. https://en.wikipedia.org/wiki/Confusion_matrix

Powyższymi pojęciami będziemy się posługiwali definiując precision i recall. Uzupełnijmy tabelę przykładowymi liczbami.

Confusion matrix, tabela błędów klasyfikatora z wartościami liczbowymi
Confusion matrix z wartościami liczbowymi jakiegoś klasyfikatora

Najlepiej czytać tę tabelę wierszowo. Czyli w sumie 999 elementów zostało zakwalifikowanych do klasy A (predicted as A), a tylko 1 element do klasy B. W tym 990 zostało oznaczonych jako A będąc rzeczywiście w klasie A oraz 9 należących do klasy B. Tylko 1 obiekt z klasy B został rozpoznany jako B i 0 elementów z klasy A zostało rozpoznanych jako B.

Miara precision odpowiada za dokładność rozpoznania klasy A, czyli jaką część stanowią poprawnie przewidziane elementy TP (true positive) do wszystkich oznaczonych jako A przez klasyfikator sumy TP+FP (true positive + False positive)

Miara recall (nazywana także: sensitivity czy true positive rate ) informuje nas ile elementów z danej klasy zostało poprawnie rozpoznanych. Wyrażana jest jako stosunek TP/(TP+FN)

Definicje wzorów – precision i recall

Pierwotnie w statystyce precision i recall odnosiło się do klasy pozytywnej, ale bardzo łatwo je uogólnić na wiele klas. I tak dla klasy A i B wzory wyglądają następująco. Wystarczy zsumować i podzielić odpowiednie komórki dla poszczególnych klas.

Definicja precision i recall dla klasyfikatora binarnego
Definicja precision i recall dla klasyfikatora binarnego

Zastanówmy się przez chwilę nad powyższymi wzorami:

  • precision dla klasy A, jest to stosunek poprawnie sklasyfikowanych elementów z A (TP) do wszystkich, które nasz klasyfikator oznaczył jako A (TP+FP)
  • recall dla klasy A, jest to stosunek poprawnie rozpoznanych elementów z A (TP) do wszystkich, które powinien rozpoznać, czyli do całej klasy A (TP+FN)

Podobnie jest z klasą B

  • precision dla klasy B, jest to stosunek poprawnie sklasyfikowanych elementów z B (TN) do wszystkich, które nasz klasyfikator oznaczył jako B (TN+FN)
  • recall dla klasy B, jest to stosunek poprawnie rozpoznanych elementów z B (TN) do wszystkich, które powinien rozpoznać, czyli do całej klasy B (TN+FP)

Podstawiająć liczby powinny wam wyjść wartości

Jeżeli chcecie pobawić się liczbami to przygotowałem pomocnego excela, do którego możecie wstawić swoje wartości i podejrzeć formuły: https://docs.google.com/spreadsheets/d/1ufHV2krvbtr7jPF-KBkK1IOHuPI4cxTjtdCuNZCizLo/edit?usp=sharing

One Ring to rule them all – miara F1

Uuu Panie, wszystko super, tylko jak jesteś taki mądry to powiedz jak mam ogarnąć 4 miary zamiast jednej. Jak porównać do siebie dwa klasyfikatory?
Sprawa jest prosta, gdy wszystkie wartości są dla jednego z nich większe, ale co w sytuacji, gdy w jednym większe jest precision dla klasy „A”, a w drugim recall.

Weź głęboki oddech i się uspokój. Zaraz dam Ci rozwiązanie.

Oto magiczne rozwiązanie: uśrednij wyniki!
Ale aby nie było za prosto, nie wystarczy tutaj zwykła średnia arytmetyczna dla precision i recall. Lepiej zastosować średnią harmoniczną.
A dlaczego tak? Szczegółową odpowiedź znajdziesz na stack overflow: Why is the F-Measure a harmonic mean and not an arithmetic mean of the Precision and Recall measures?

Ja tylko przytoczę dwa wykresy funkcji dla średniej arytmetycznej i harmonicznej.

Wykresy 2D dla średniej arytmetycznej (z lewej) i średniej harmonicznej (z prawej).

Co z nich wynika? Zauważcie, że średnia harmoniczna bardziej „karze” gdy jeden z wyników jest zły (bliski zera). Wartość średniej wtedy jest także mała (ciemnoniebieskie obrzeża). Dzięki tej właściwości możemy szybko zauważyć, że coś jest nie tak z którąś z wartości (precision bądź recall).

A oto proszę państwa wzór na F1:

{\displaystyle F_{1}=\left({\frac {2}{\mathrm {recall} ^{-1}+\mathrm {precision} ^{-1}}}\right)=2\cdot {\frac {\mathrm {precision} \cdot \mathrm {recall} }{\mathrm {precision} +\mathrm {recall} }}}

W bardziej ogólnym przypadku Fβ, gdy chcemy wskazać co jest dla nas ważniejsze precision czy recall.

Jeżeli obie miary są ważne to podstawiamy za β=1, jeżeli bardziej zależy nam na precission to Beta powinna być z przedziału [0,1], zaś w przeciwnym przypadku gdy bardziej zależy na Recall to β>1.
Zazwyczaj mamy trzy sytuację:

  • β=1 – precision i recall tak samo ważne
  • β=0.5 precision ważniejsze
  • β=2 recall ważniejszy

Uśredniona miara F1

W poprzedniej sekcji omówiliśmy miarę F1, ale tylko dla jednej klasy. Precision i recall możemy policzyć dla każdej klasy z osobna i otrzymamy dwie wartości F1 (dla klasy A i B). Chcąc mieć tylko jedną liczbę dla naszego klasyfikatora binarnego możemy dokonać uśrednienia dwóch F1. Obliczymy w ten sposób macro average F1.

Dla tych, co chcą wgłębić się w bebechy miary F1 polecam artykuł https://www.mikulskibartosz.name/f1-score-explained/

Problem wieloklasowy

Podobnie jak dla dwóch klas powyższe miary: precision, recall i F1 można policzyć dla wielu klas. W przykładowym arkuszu kalkulacyjnym https://docs.google.com/spreadsheets/d/1ufHV2krvbtr7jPF-KBkK1IOHuPI4cxTjtdCuNZCizLo/edit#gid=372756307

jest zakładka multiclass_classification, w której podaję przykład jak to dokładnie policzyć. Przeanalizujcie sami, sądzę, że po powyższej lekturze ze zrozumieniem nie będziecie mieli problemu.

Jak policzyć precision, recall i F1 w scikit-learn?

Z wykorzystaniem biblioteki scikit-learn to banalnie proste. Wystarczy przygotować tylko dane wejściowe:

  • y_true – czyli rzeczywiste etykiety
  • y_pred – etykiety przewidziane przez klasyfikator.

Resztą zajmie się już sklearn! Wykorzystaj metodę classification_report z mudułu sklearn.metrics
Poniższy kod znajdziesz także w projekcie na moim githubie https://github.com/ksopyla/scikit-learn-tutorial/blob/master/metrics/metrics.py

import sklearn.metrics as skm
import numpy as np

#%% #binary problem
# true labels
y_true = np.array([0, 0, 1, 0, 0, 1, 0, 0, 1, 1], dtype=float)

# classificator predict scores for each object
y_scores = np.array([0.01, 0.12, 0.89, .99, .05, .76, .14, .87, .44, .32])

# casts scores to labels,
y_pred = y_scores > 0.5

# compute confusion_matrix
cm = skm.confusion_matrix(y_true, y_pred)
print(cm)

# compute classification 
print(skm.classification_report(y_true, y_pred))

report = skm.classification_report(y_true, y_pred, output_dict=True)
print(report)

Potrzebujemy dwóch tablic:

  • y_true – tablica z rzeczywistymi wartościami klas
  • y_pred – tablica z przewidzianymi klasam

Następnie liczymy i wyświetlamy confusion matrix oraz raport klasyfikacji. Zauważcie, że scikit learn domyślnie za klasę pozytywną bierze wartości „1”. To i wiele innych domyślnych ustawień można łatwo zmienić przekazując do metody dodatkowe parametry. Warto zwrócić uwagę na następujące:

  • output_dict=True – zwróci nam słownik z poszczególnymi wartośiami
  • target_names=[’klasa A’, 'klasa B’] – możemy podać nazwy dla naszych klas

Podsumowanie

We wpisie przedstawiłem idea oraz intuicję podstawowych miar używanych podczas oceny klasyfikatorów: precision, recall i miarę F1. Zachęcam do „pobawienia” się udostępnionym arkuszem kalkulacyjnym w celu poczucia jak te miary się zmieniają w zależności od wartości: true positive, false positive, false negative i true negative. Warto także poeksperymentować z parametrami do metod w powyższych przykładach. Powodzenia w nauce.

Jeżeli uważasz ten wpis za wartościowy to Zasubskrybuj bloga. Dostaniesz informacje o nowych artykułach.

Join 100 other subscribers

Ps. Obraz Steve Buissinne z Pixabay

7 Comments Precision, recall i F1 – miary oceny klasyfikatora

  1. biesek

    We fragmencie o tłumaczeniu możliwych wariantów predykcji pojawiło się wtrącone „Confusion matrix z wartościami liczbowymi jakiegoś klasyfikatora” 🙂

    Reply
    1. ksopyla

      O dzięki, już poprawiam.
      Niestety przy dłuższym tekście łatwo o wklejenie czegoś tam gdzie nie trzeba ;(

  2. Daniel

    Mam pytanie do arkusza excel dla klasyfikacji wieloklasowej. Czy formuła dla komórek J11, K11 i L11 nie powinna obejmować średniej z klas A, B i C? Bo jest wzięta tylko A i B.

    Reply

Ciekawe, wartościowe, podziel się proszę opinią!

Witryna wykorzystuje Akismet, aby ograniczyć spam. Dowiedz się więcej jak przetwarzane są dane komentarzy.