02 · Dane · 4 min czytania · aktualizacja
Co zrobić, gdy w danych jedna klasa jest bardzo rzadka (niezrównoważone klasy)?
W skrócie
Gdy jedna klasa jest rzadka, trafność kłamie, a model domyślnie ją ignoruje. Pomagają właściwe metryki, wagi klas, zmiana progu decyzji i ostrożny resampling.
Co to jest
Niezrównoważone klasy (ang. imbalanced data) to sytuacja, w której jedna klasa występuje znacznie rzadziej niż pozostałe: oszustwa wśród transakcji (często poniżej 1%), rzadkie choroby, awarie maszyn, kliknięcia w reklamę. Zwykle to właśnie rzadka klasa jest tą, która nas interesuje.
Problem nie polega na samej rzadkości, tylko na tym, że standardowe narzędzia — trafność jako metryka, próg 0,5, nieważona funkcja straty — są do takich danych źle dopasowane. Model uczy się, że najbezpieczniej jest prawie zawsze odpowiadać „klasa częsta”, a metryka mu przyklaskuje.
Intuicja: detektor, który przy 1% oszustw zawsze mówi „to nie oszustwo”, ma 99% trafności i jest całkowicie bezużyteczny.
Mechanizm — dlaczego tak działa
Funkcja straty to suma (lub średnia) po przykładach. Jeśli 95% przykładów to klasa częsta, to ona dominuje w gradiencie; błędy na rzadkiej klasie są dla optymalizatora prawie niewidoczne. Model z dobrze skalibrowanymi prawdopodobieństwami będzie też poprawnie przewidywał niskie prawdopodobieństwa klasy rzadkiej — rzadko przekraczające 0,5. Próg 0,5 minimalizuje liczbę błędów tylko przy równych kosztach obu pomyłek, a przy wykrywaniu choroby czy oszustwa przeoczenie zwykle kosztuje znacznie więcej niż fałszywy alarm.
Rozwiązania działają na trzech poziomach. Metryka: zamiast trafności — czułość (recall), precyzja, F1, zrównoważona trafność (średnia czułości klas), pole pod krzywą precyzja–czułość. Decyzja: przesunięcie progu tak, by odpowiadał kosztom błędów; to często najprostsza i najskuteczniejsza zmiana. Uczenie: wagi klas w funkcji straty (rzadka klasa liczy się mocniej) albo resampling — nadpróbkowanie rzadkiej klasy (losowe lub syntetyczne, np. SMOTE) czy podpróbkowanie częstej.
Ważne rozróżnienie: wagi klas i resampling zmieniają głównie to, gdzie model stawia granicę, a nie to, jak dobrze porządkuje przypadki od najmniej do najbardziej podejrzanych. Jeśli model już dobrze rankuje (wysokie pole pod krzywą), podobny efekt da samo przesunięcie progu. Ceną wag i resamplingu jest kalibracja: przewidywane prawdopodobieństwa przestają odpowiadać rzeczywistym częstościom, co szkodzi, gdy prawdopodobieństwo jest potrzebne samo w sobie (np. do wyceny ryzyka).
Przy ocenie trzeba stosować podział warstwowy (stratified), by każdy fold miał podobny odsetek rzadkiej klasy, i nigdy nie resamplować zbioru testowego — test ma odzwierciedlać rzeczywiste proporcje.
Na przykładzie
Pełny zbiór Breast Cancer Wisconsin ma 212 guzów złośliwych na 569 (37%), więc nie jest mocno niezrównoważony. Aby pokazać problem, zostawiamy wszystkie 357 łagodnych i losujemy tylko 30 złośliwych — klasa rzadka stanowi wtedy 7,8%. Klasyfikator zawsze mówiący „łagodny” ma 92,2% trafności i zerową czułość.
Regresja logistyczna (10-krotna walidacja krzyżowa, średnia z 20 losowań podzbioru) przy progu 0,5 przeocza średnio 6,9 z 30 złośliwych guzów, nie dając przy tym prawie żadnych fałszywych alarmów. Z wagami klas class_weight='balanced' przeoczeń jest tylko 1,6, kosztem 5,4 fałszywych alarmów. Średnia precyzja (pole pod krzywą precyzja–czułość) prawie się nie zmienia: 0,966 bez wag i 0,970 z wagami. Model nie stał się „mądrzejszy” — przesunął granicę na korzyść rzadkiej klasy, co przy diagnozie raka jest właśnie tym, czego chcemy.
Dane: Breast Cancer Wisconsin (diagnostyka raka piersi)
W praktyce
- Podział i walidacja:
train_test_split(..., stratify=y),StratifiedKFold. - Metryki:
classification_report,balanced_accuracy_score,average_precision_score,precision_recall_curve; trafność traktuj podejrzliwie. - Wagi:
class_weight='balanced'wLogisticRegression,SVC,RandomForestClassifier; w gradient boostinguscale_pos_weight(XGBoost, LightGBM); w PyTorchpos_weightwBCEWithLogitsLoss. - Próg: wybierz na zbiorze walidacyjnym z krzywej precyzja–czułość albo
TunedThresholdClassifierCV(scikit-learn od 1.5). - Resampling (biblioteka imbalanced-learn) tylko wewnątrz foldów treningowych, przez
imblearn.pipeline.Pipeline. - Typowy błąd: raportowanie trafności i ROC AUC bez czułości i precyzji przy bardzo rzadkiej klasie.
Najczęstsze pytania
- Od jakiego odsetka klasy mówimy o niezrównoważeniu?
- Nie ma sztywnej granicy. Proporcja 60/40 zwykle nie wymaga zabiegów, przy 90/10 trafność już mocno wprowadza w błąd, a przy 99/1 i rzadszych potrzebne są właściwe metryki i przemyślany próg. Liczy się też bezwzględna liczba przykładów rzadkiej klasy.
- Co jest lepsze: wagi klas czy SMOTE?
- Często dają podobne wyniki, a wagi są prostsze i nie tworzą sztucznych danych. Warto zacząć od dobrej metryki i progu, potem wag; resampling sprawdzać jako kolejną opcję w walidacji krzyżowej.
- Czy zbieranie większej liczby danych pomaga?
- Najbardziej pomaga zebranie większej liczby przykładów rzadkiej klasy. Dodawanie kolejnych przykładów klasy częstej zwykle daje niewiele.
Źródła
- He H., Garcia E. A. (2009). „Learning from Imbalanced Data”. IEEE Transactions on Knowledge and Data Engineering, 21(9), 1263–1284.
- Elkan C. (2001). „The Foundations of Cost-Sensitive Learning”. Proceedings of IJCAI 2001.
- van den Goorbergh R., van Smeden M., Timmerman D., Van Calster B. (2022). „The harm of class imbalance corrections for risk prediction models: illustration and simulation using logistic regression”. Journal of the American Medical Informatics Association, 29(9).
- Géron A. „Hands-On Machine Learning with Scikit-Learn, Keras, and TensorFlow”, 3rd ed., 2022, rozdz. 3.
- Dokumentacja imbalanced-learn: https://imbalanced-learn.org/stable/