Jak obliczyć precyzję, odtworzenie, dokładność i wynik f1 dla przypadku wieloklasowego za pomocą narzędzia Scikit Learn?

109

Pracuję nad problemem analizy nastrojów, dane wyglądają następująco:

label instances
    5    1190
    4     838
    3     239
    1     204
    2     127

Więc moje dane są niezrównoważone, ponieważ 1190 instancessą oznaczone 5. Do klasyfikacji używam SVC firmy scikit . Problem polega na tym, że nie wiem, jak zrównoważyć moje dane we właściwy sposób, aby dokładnie obliczyć precyzję, pamięć, dokładność i wynik f1 dla przypadku wieloklasowego. Więc spróbowałem następujących podejść:

Pierwszy:

    wclf = SVC(kernel='linear', C= 1, class_weight={1: 10})
    wclf.fit(X, y)
    weighted_prediction = wclf.predict(X_test)

print 'Accuracy:', accuracy_score(y_test, weighted_prediction)
print 'F1 score:', f1_score(y_test, weighted_prediction,average='weighted')
print 'Recall:', recall_score(y_test, weighted_prediction,
                              average='weighted')
print 'Precision:', precision_score(y_test, weighted_prediction,
                                    average='weighted')
print '\n clasification report:\n', classification_report(y_test, weighted_prediction)
print '\n confussion matrix:\n',confusion_matrix(y_test, weighted_prediction)

Druga:

auto_wclf = SVC(kernel='linear', C= 1, class_weight='auto')
auto_wclf.fit(X, y)
auto_weighted_prediction = auto_wclf.predict(X_test)

print 'Accuracy:', accuracy_score(y_test, auto_weighted_prediction)

print 'F1 score:', f1_score(y_test, auto_weighted_prediction,
                            average='weighted')

print 'Recall:', recall_score(y_test, auto_weighted_prediction,
                              average='weighted')

print 'Precision:', precision_score(y_test, auto_weighted_prediction,
                                    average='weighted')

print '\n clasification report:\n', classification_report(y_test,auto_weighted_prediction)

print '\n confussion matrix:\n',confusion_matrix(y_test, auto_weighted_prediction)

Trzeci:

clf = SVC(kernel='linear', C= 1)
clf.fit(X, y)
prediction = clf.predict(X_test)


from sklearn.metrics import precision_score, \
    recall_score, confusion_matrix, classification_report, \
    accuracy_score, f1_score

print 'Accuracy:', accuracy_score(y_test, prediction)
print 'F1 score:', f1_score(y_test, prediction)
print 'Recall:', recall_score(y_test, prediction)
print 'Precision:', precision_score(y_test, prediction)
print '\n clasification report:\n', classification_report(y_test,prediction)
print '\n confussion matrix:\n',confusion_matrix(y_test, prediction)


F1 score:/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:676: DeprecationWarning: The default `weighted` averaging is deprecated, and from version 0.18, use of precision, recall or F-score with multiclass or multilabel data or pos_label=None will result in an exception. Please set an explicit value for `average`, one of (None, 'micro', 'macro', 'weighted', 'samples'). In cross validation use, for instance, scoring="f1_weighted" instead of scoring="f1".
  sample_weight=sample_weight)
/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:1172: DeprecationWarning: The default `weighted` averaging is deprecated, and from version 0.18, use of precision, recall or F-score with multiclass or multilabel data or pos_label=None will result in an exception. Please set an explicit value for `average`, one of (None, 'micro', 'macro', 'weighted', 'samples'). In cross validation use, for instance, scoring="f1_weighted" instead of scoring="f1".
  sample_weight=sample_weight)
/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:1082: DeprecationWarning: The default `weighted` averaging is deprecated, and from version 0.18, use of precision, recall or F-score with multiclass or multilabel data or pos_label=None will result in an exception. Please set an explicit value for `average`, one of (None, 'micro', 'macro', 'weighted', 'samples'). In cross validation use, for instance, scoring="f1_weighted" instead of scoring="f1".
  sample_weight=sample_weight)
 0.930416613529

Jednak otrzymuję takie ostrzeżenia:

/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:1172:
DeprecationWarning: The default `weighted` averaging is deprecated,
and from version 0.18, use of precision, recall or F-score with 
multiclass or multilabel data or pos_label=None will result in an 
exception. Please set an explicit value for `average`, one of (None, 
'micro', 'macro', 'weighted', 'samples'). In cross validation use, for 
instance, scoring="f1_weighted" instead of scoring="f1"

Jak mogę poprawnie radzić sobie z moimi niezrównoważonymi danymi, aby poprawnie obliczyć metryki klasyfikatora?

nowy_with_python
źródło
Dlaczego więc nie dodać averageparametru w trzecim przypadku?
yangjie
1
@yangjie I dont know. Po prostu sprawdzam dokumentację, ale nie rozumiem, jak prawidłowo używać wskaźników dla niezrównoważonych danych. Czy mógłbyś podać szersze wyjaśnienie i przykład? Dzięki!
new_with_python

Odpowiedzi:

164

Myślę, że istnieje wiele nieporozumień dotyczących tego, które ciężary są używane do czego. Nie jestem pewien, czy dokładnie wiem, co Cię trapi, więc zamierzam poruszyć różne tematy, wytrzymajcie;).

Wagi klas

Wagi z class_weightparametru służą do trenowania klasyfikatora . Nie są one używane do obliczania jakichkolwiek używanych przez ciebie metryk : przy różnych wagach klas liczby będą się różnić po prostu dlatego, że klasyfikator jest inny.

Zasadniczo w każdym klasyfikatorze typu scikit, wagi klas są używane do informowania modelu, jak ważna jest klasa. Oznacza to, że w trakcie szkolenia klasyfikator dołoży dodatkowych starań, aby odpowiednio sklasyfikować zajęcia z dużymi wagami.
Sposób, w jaki to robią, zależy od algorytmu. Jeśli chcesz uzyskać szczegółowe informacje o tym, jak to działa w przypadku SVC, a dokument nie ma dla Ciebie sensu, możesz o tym wspomnieć.

Metryki

Gdy masz już klasyfikator, chcesz wiedzieć, jak dobrze działa. Tutaj można używać metryki pan wspomniał: accuracy, recall_score, f1_score...

Zwykle, gdy rozkład klas jest niezrównoważony, dokładność jest uważana za zły wybór, ponieważ daje wysokie wyniki modelom, które tylko przewidują najczęstszą klasę.

Nie będę szczegółowo opisywać wszystkich tych wskaźników, ale zauważę, że z wyjątkiem accuracy, są one naturalnie stosowane na poziomie klasy: jak widać w printraporcie klasyfikacyjnym, są one zdefiniowane dla każdej klasy. Opierają się na pojęciach takich jak true positiveslub, false negativektóre wymagają określenia, która klasa jest pozytywna .

             precision    recall  f1-score   support

          0       0.65      1.00      0.79        17
          1       0.57      0.75      0.65        16
          2       0.33      0.06      0.10        17
avg / total       0.52      0.60      0.51        50

Ostrzeżenie

F1 score:/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:676: DeprecationWarning: The 
default `weighted` averaging is deprecated, and from version 0.18, 
use of precision, recall or F-score with multiclass or multilabel data  
or pos_label=None will result in an exception. Please set an explicit 
value for `average`, one of (None, 'micro', 'macro', 'weighted', 
'samples'). In cross validation use, for instance, 
scoring="f1_weighted" instead of scoring="f1".

Otrzymujesz to ostrzeżenie, ponieważ używasz wyniku f1, odwołania i precyzji bez definiowania sposobu ich obliczania! Pytanie mogłoby zostać sformułowane na nowo: jak z powyższego raportu klasyfikacyjnego wyprowadzić jedną liczbę globalną dla wyniku f1? Mógłbyś:

  1. Weź średnią wyników f1 dla każdej klasy: to avg / totalwynik powyżej. Nazywa się to również uśrednianiem makro .
  2. Oblicz wynik f1, używając globalnej liczby prawdziwych wyników / fałszywych wyników negatywnych itp. (Sumujesz liczbę prawdziwych / fałszywie negatywnych wyników dla każdej klasy). Aka mikro uśrednianie.
  3. Oblicz średnią ważoną wyniku f1. Użycie 'weighted'w scikit-learn waży wynik f1 dzięki wsparciu klasy: im więcej elementów ma klasa, tym ważniejszy jest wynik f1 dla tej klasy w obliczeniach.

Oto 3 opcje w scikit-learn, ostrzeżenie mówi, że musisz wybrać jedną . Musisz więc określić averageargument dla metody punktacji.

To, który wybierzesz, zależy od tego, jak chcesz mierzyć wydajność klasyfikatora: na przykład uśrednianie makro nie bierze pod uwagę nierównowagi klas, a wynik f1 klasy 1 będzie tak samo ważny jak wynik f1 klasy 5. Jeśli używasz średniej ważonej, będziesz mieć większe znaczenie dla klasy 5.

Cała specyfikacja argumentów w tych metrykach nie jest teraz super-przejrzysta w scikit-learn, zgodnie z dokumentacją poprawi się w wersji 0.18. Usuwają niektóre nieoczywiste standardowe zachowania i wydają ostrzeżenia, aby programiści to zauważyli.

Obliczanie wyników

Ostatnią rzeczą, o której chciałbym wspomnieć (możesz to pominąć, jeśli jesteś tego świadomy), jest to, że wyniki mają znaczenie tylko wtedy, gdy są obliczane na danych, które klasyfikator nigdy nie widział . Jest to niezwykle ważne, ponieważ każdy wynik uzyskany na podstawie danych użytych do dopasowania klasyfikatora jest całkowicie nieistotny.

Oto sposób na zrobienie tego za pomocą StratifiedShuffleSplit, który daje losowe podziały danych (po tasowaniu), które chronią dystrybucję etykiet.

from sklearn.datasets import make_classification
from sklearn.cross_validation import StratifiedShuffleSplit
from sklearn.metrics import accuracy_score, f1_score, precision_score, recall_score, classification_report, confusion_matrix

# We use a utility to generate artificial classification data.
X, y = make_classification(n_samples=100, n_informative=10, n_classes=3)
sss = StratifiedShuffleSplit(y, n_iter=1, test_size=0.5, random_state=0)
for train_idx, test_idx in sss:
    X_train, X_test, y_train, y_test = X[train_idx], X[test_idx], y[train_idx], y[test_idx]
    svc.fit(X_train, y_train)
    y_pred = svc.predict(X_test)
    print(f1_score(y_test, y_pred, average="macro"))
    print(precision_score(y_test, y_pred, average="macro"))
    print(recall_score(y_test, y_pred, average="macro"))    

Mam nadzieję że to pomoże.

ldirer
źródło
Jak w przypadku wieloklasowej określić wagę klasy? Np. Co class_weight={1:10}oznacza dla danych, które mają 3 klasy?
Aziz Javed
Czy w ogóle można uzyskać oceny dokładności dotyczące etykiet?
Ankur Sinha,
Czy możesz wyraźniej wyjaśnić, jak działa mikro. Nie wspominasz też o binarnych
pokornych
Dla mnie tasowanie warstwowe powodowało problemy, więc przełączyłem się z powrotem do pokazanego podziału pociąg-test ValueError: The least populated class in y has only 1 member, which is too few. The minimum number of labels for any class cannot be less than 2.. Działa dobrze z podziałem testu pociągu, ale czy ktoś może mi pomóc, dlaczego otrzymuję ten błąd z SSS? Dzięki.
Akash Kandpal
Cześć, przetestowałem twój kod, ale mam ten komunikat o błędzie C: \ Users \\ Anaconda3 \ lib \ site-packages \ sklearn \ metrics \ Classification.py: 976: DeprecationWarning: Od wersji 0.18 dane binarne nie będą obsługiwane specjalnie podczas używania uśredniona precyzja / przywołanie / wynik F. Użyj wartości Average = 'binary', aby zgłosić tylko pozytywne wyniki klasy.
``
73

Wiele bardzo szczegółowych odpowiedzi tutaj, ale myślę, że nie odpowiadasz na właściwe pytania. Jak rozumiem pytanie, istnieją dwie obawy:

  1. Jak rozwiązać problem z wieloma klasami?
  2. Jak sobie radzić z niezrównoważonymi danymi?

1.

Możesz używać większości funkcji oceniających w scikit-learn zarówno z problemami wieloklasowymi, jak i problemami z pojedynczą klasą. Dawny.:

from sklearn.metrics import precision_recall_fscore_support as score

predicted = [1,2,3,4,5,1,2,1,1,4,5] 
y_test = [1,2,3,4,5,1,2,1,1,4,1]

precision, recall, fscore, support = score(y_test, predicted)

print('precision: {}'.format(precision))
print('recall: {}'.format(recall))
print('fscore: {}'.format(fscore))
print('support: {}'.format(support))

W ten sposób otrzymasz namacalne i możliwe do zinterpretowania liczby dla każdej z klas.

| Label | Precision | Recall | FScore | Support |
|-------|-----------|--------|--------|---------|
| 1     | 94%       | 83%    | 0.88   | 204     |
| 2     | 71%       | 50%    | 0.54   | 127     |
| ...   | ...       | ...    | ...    | ...     |
| 4     | 80%       | 98%    | 0.89   | 838     |
| 5     | 93%       | 81%    | 0.91   | 1190    |

Następnie...

2.

... możesz stwierdzić, czy niezrównoważone dane są problemem. Jeśli punktacja dla mniej reprezentowanych klas (klasa 1 i 2) jest niższa niż dla klas z większą liczbą próbek szkoleniowych (klasa 4 i 5), to wiesz, że niezrównoważone dane są w rzeczywistości problemem i możesz odpowiednio postępować, ponieważ opisane w niektórych innych odpowiedziach w tym wątku. Jednakże, jeśli ten sam rozkład klas jest obecny w danych, które chcesz przewidzieć, Twoje niezrównoważone dane szkoleniowe są dobrym reprezentantem danych, a zatem asymetria jest dobrą rzeczą.

Wonderkid2
źródło
1
Świetny post i dobrze powiedziane. Dziękuję
Alvis
1
Hej, tylko pytanie dodatkowe: w jaki sposób wydrukowałeś etykiety za pomocą precision_recall_fscore_support? Czy etykiety są drukowane na zamówienie?
BigD
@BigD Tak, zobacz scikit-learn.org/stable/modules/generated/ ... na samym dole. Ustaw average=Nonei zdefiniuj etykiety, a następnie uzyskasz dane, których szukasz, dla każdej z określonych etykiet.
wonderkid2
Czy w ogóle można uzyskać oceny dokładności dotyczące etykiet?
Ankur Sinha,
@trollster Nie jestem pewien, co masz na myśli? Czy nie jest to, co pokazuję w wynikach dokładności etykiet w odpowiedzi?
wonderkid2
16

Postawione pytanie

Odpowiadając na pytanie „jaki miernik należy zastosować do klasyfikacji wieloklasowej z niezrównoważonymi danymi”: Makro-miara F1. Można również użyć makroprecyzji i przywoływania makr, ale nie są one tak łatwe do interpretacji, jak w przypadku klasyfikacji binarnej, są już włączone do miary F, a nadmiar metryk komplikuje porównanie metod, dostrajanie parametrów i tak dalej.

Uśrednianie w skali mikro jest wrażliwe na nierównowagę klas: jeśli na przykład Twoja metoda działa dobrze w przypadku najpopularniejszych etykiet i całkowicie przeszkadza innym, metryki uśrednione w skali mikro dają dobre wyniki.

Uśrednianie ważenia nie jest odpowiednie dla niezrównoważonych danych, ponieważ jest ważone według liczby etykiet. Ponadto jest on zbyt trudny do zinterpretowania i niepopularny: na przykład nie ma wzmianki o takim uśrednieniu w poniższej bardzo szczegółowej ankiecie, którą gorąco polecam:

Sokolova, Marina i Guy Lapalme. „Systematyczna analiza miar wydajności dla zadań klasyfikacyjnych”. Przetwarzanie informacji i zarządzanie 45.4 (2009): 427-437.

Pytanie dotyczące aplikacji

Jednak wracając do twojego zadania, zbadałbym 2 tematy:

  1. metryki powszechnie używane do konkretnego zadania - pozwalają (a) porównać twoją metodę z innymi i zrozumieć, czy zrobisz coś złego, oraz (b) nie badać tego samodzielnie i ponownie wykorzystywać cudzych ustaleń;
  2. koszt różnych błędów twoich metod - na przykład przypadek użycia twojej aplikacji może opierać się tylko na recenzjach 4- i 5-gwiazdkowych - w tym przypadku dobra metryka powinna liczyć tylko te 2 etykiety.

Powszechnie używane metryki. Jak mogę wywnioskować po przejrzeniu literatury, istnieją 2 główne wskaźniki oceny:

  1. Dokładność , z jakiej się korzysta np

Yu, April i Daryl Chang. „Wieloklasowe przewidywanie nastrojów przy użyciu Yelp Business”.

( link ) - zauważ, że autorzy pracują z prawie takim samym rozkładem ocen, patrz Rysunek 5.

Pang, Bo i Lillian Lee. „Widzenie gwiazd: wykorzystywanie relacji klasowych do kategoryzacji nastrojów w odniesieniu do skal ocen”. Materiały z 43. dorocznego spotkania Stowarzyszenia Lingwistyki Komputerowej. Stowarzyszenie Lingwistyki Obliczeniowej, 2005.

( link )

  1. MSE (lub rzadziej Mean Absolute Error - MAE ) - patrz np.

Lee, Moontae i R. Grafe. „Wieloklasowa analiza nastrojów z recenzjami restauracji”. Projekty końcowe z CS N 224 (2010).

( link ) - badają zarówno dokładność, jak i MSE, uważając to drugie za lepsze

Pappas, Nikolaos, Rue Marconi i Andrei Popescu-Belis. „Explaining the Stars: Weighted Multiple Instance Learning for Aspect Based Sentiment Analysis”. Materiały z konferencji 2014 nt. Metod empirycznych w przetwarzaniu języka naturalnego. Nr EPFL-CONF-200899. 2014.

( link ) - wykorzystują scikit-learning do oceny i podejścia bazowego i stwierdzają, że ich kod jest dostępny; jednak nie mogę jej znaleźć, więc jeśli potrzebujesz, napisz list do autorów, praca jest całkiem nowa i wydaje się być napisana w Pythonie.

Koszt różnych błędów . Jeśli bardziej zależy Ci na unikaniu poważnych błędów, np. Ocenianie oceny od 1 do 5 gwiazdek lub coś w tym rodzaju, spójrz na MSE; jeśli różnica ma znaczenie, ale nie tak bardzo, spróbuj MAE, ponieważ nie ma różnicy kwadratowej; w przeciwnym razie pozostań przy dokładności.

O podejściach, a nie metrykach

Wypróbuj metody regresji, np. SVR , ponieważ generalnie przewyższają one klasyfikatory wieloklasowe, takie jak SVC lub OVA SVM.

Nikita Astrakhantsev
źródło
13

Przede wszystkim jest trochę trudniej, używając samej analizy liczenia, aby stwierdzić, czy dane są niezrównoważone, czy nie. Na przykład: 1 na 1000 pozytywnych obserwacji to tylko szum, błąd lub przełom w nauce? Nigdy nie wiesz.
Dlatego zawsze lepiej jest wykorzystać całą dostępną wiedzę i mądrze wybrać jej status.

Dobra, a co jeśli jest naprawdę niezrównoważony?
Jeszcze raz - spójrz na swoje dane. Czasami można znaleźć jedną lub dwie obserwacje pomnożone sto razy. Czasami warto stworzyć fałszywe obserwacje jednoklasowe.
Jeśli wszystkie dane są czyste, następnym krokiem jest użycie wag klas w modelu predykcyjnym.

A co z metrykami wieloklasowymi?
Z mojego doświadczenia wynika, że ​​żadne z Twoich wskaźników nie jest zwykle używane. Są dwa główne powody.
Po pierwsze: zawsze lepiej jest pracować z prawdopodobieństwami niż z solidną prognozą (bo jak inaczej można oddzielić modele z predykcją 0,9 i 0,6, jeśli oba dają tę samą klasę?).
Po drugie: znacznie łatwiej jest porównać modele predykcyjne i zbudować nowe zależne tylko od jednej dobrej metryki.
Z mojego doświadczenia mogę polecić logloss lub MSE (lub po prostu średni kwadratowy błąd).

Jak naprawić ostrzeżenia sklearn?
Po prostu (jak zauważył yangjie) nadpisz averageparametr jedną z następujących wartości: 'micro'(oblicz metryki globalnie), 'macro'(oblicz metryki dla każdej etykiety) lub 'weighted'(tak samo jak makro, ale z automatycznymi wagami).

f1_score(y_test, prediction, average='weighted')

Wszystkie ostrzeżenia pojawiły się po wywołaniu funkcji metryk z averagewartością domyślną, 'binary'która jest nieodpowiednia do przewidywania wieloklasowego.
Powodzenia i dobrej zabawy z uczeniem maszynowym!

Edycja:
znalazłem inną rekomendację odpowiadającą, aby przejść na metody regresji (np. SVR), z którymi nie mogę się zgodzić. O ile dobrze pamiętam, nie ma nawet czegoś takiego jak regresja wieloklasowa. Tak, istnieje regresja wielopoziomowa, która jest znacznie inna i tak, w niektórych przypadkach można przełączać się między regresją a klasyfikacją (jeśli klasy w jakiś sposób posortowane), ale jest to dość rzadkie.

To, co poleciłbym (w zakresie scikit-learn), to wypróbowanie innych bardzo potężnych narzędzi klasyfikacyjnych: wzmocnienie gradientu , losowy las (mój ulubiony), KNeighbors i wiele innych.

Następnie możesz obliczyć średnią arytmetyczną lub geometryczną między przewidywaniami i przez większość czasu uzyskasz jeszcze lepszy wynik.

final_prediction = (KNNprediction * RFprediction) ** 0.5
Vlad Mironov
źródło
1
> "przełącz się między regresją a klasyfikacją (jeśli klasy są w jakiś sposób posortowane), ale jest to dość rzadkie" Tak jest: 5> 4> 3> 2> 1. Proponuję przyjrzeć się artykułom do tego zadania - są wiele podejść regresyjnych i klasyfikacyjnych do zadania (czasami w tej samej pracy).
Nikita Astrakhantsev
Wtedy nie jest to nawet klasyfikacja wieloklasowa, ale prosta regresja.
Vlad Mironov
Tak, wewnętrznie lub z punktu widzenia ML jest to regresja, ale na ostatnim etapie konwertujemy wyniki regresji na etykiety, więc jest to klasyfikacja wieloklasowa - z punktu widzenia użytkownika lub aplikacji.
Nikita Astrakhantsev