Як впоратися з дисбалансом класів у машинному навчанні

pic

Дисбаланс класів — одна з найбільш поширених проблем у машинному навчанні. Він виникає, коли розподіл класів у наборі даних не є рівномірним, що призводить до недостатнього представлення деяких класів. Це може значно вплинути на ефективність моделей машинного навчання, особливо коли точність не є достатньою метрикою для оцінки.

У цій статті ми розглянемо різні техніки боротьби з дисбалансом класів, використовуючи приклади та код на Python для демонстрації їх реалізації.

Розуміння дисбалансу класів

Розглянемо задачу бінарної класифікації, де потрібно передбачити, чи буде клієнт банку не виконувати свої зобов’язання за кредитом. Припустимо, що наш набір даних має такий розподіл класів:

  • Defaulted (Меншість): 1,000 прикладів
  • Not Defaulted (Більшість): 9,000 прикладів

У таких випадках модель може постійно передбачати клас більшості (Not Defaulted) і досягати 90% точності, хоча її ефективність для класу меншості залишатиметься поганою.

Чому дисбаланс класів є проблемою?

  • Ухил до класу більшості: Більшість алгоритмів машинного навчання намагаються мінімізувати загальну помилку, що може призвести до ігнорування класу меншості, який є класом інтересу.
  • Зміщені метрики: Точність не завжди відображає реальну ефективність моделі на класі меншості.

Ключові метрики для оцінки моделей на дисбалансованих наборах даних включають (не Точність):

  • Точність (Precision)
  • Повний охоплення (Recall)
  • F1-міра (F1-score)
  • ROC-AUC

Техніки боротьби з дисбалансом класів

1. Методи на рівні даних

Ці методи спрямовані на балансування розподілу класів у навчальному наборі даних.

a. Методи ресемплінгу.

Вони полягають у видаленні зразків з класу більшості (підвибірка) та/або додаванні більше прикладів з класу меншості (перевибірка).

pic

Хоча балансування класів має свої переваги, це не без недоліків. Просте перевибірку, яке дублює випадкові екземпляри класу меншості, може призвести до перенавчання моделі на цих конкретних зразках. З іншого боку, базова підвибірка, яка випадковим чином відкидає екземпляри класу більшості, може призвести до втрати потенційно цінної інформації.

i. Перевибірка класу меншості

Перевибірка включає дублювання прикладів з класу меншості або створення синтетичних даних.

Приклад: Випадкова перевибірка з imblearn

from imblearn.over_sampling import RandomOverSampler  
from sklearn.model_selection import train_test_split  
from sklearn.ensemble import RandomForestClassifier  
from sklearn.metrics import classification_report  

# Приклад набору даних  
X = ... # Ознаки  
y = ... # Цільова змінна  

# Розподіл набору даних  
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)  

# Застосування випадкової перевибірки  
ros = RandomOverSampler(random_state=42)  
X_train_ros, y_train_ros = ros.fit_resample(X_train, y_train)  

# Навчання моделі  
model = RandomForestClassifier(random_state=42)  
model.fit(X_train_ros, y_train_ros)  

# Прогнози  
y_pred = model.predict(X_test)  
print(classification_report(y_test, y_pred))

ii. Підвибірка класу більшості

Підвибірка полягає у видаленні прикладів з класу більшості для балансування набору даних.

Приклад: Випадкова підвибірка з imblearn

from imblearn.under_sampling import RandomUnderSampler  
# Застосування випадкової підвибірки  
rus = RandomUnderSampler(random_state=42)  
X_train_rus, y_train_rus = rus.fit_resample(X_train, y_train)  
# Навчання та оцінка  
model.fit(X_train_rus, y_train_rus)  
y_pred = model.predict(X_test)  
print(classification_report(y_test, y_pred))

iii. Підвибірка: Посилання Tomek

Посилання Tomek визначають пари найближчих сусідів з різних класів, які знаходяться дуже близько один до одного.
Видалення зразка з класу більшості в кожній парі допомагає очистити набір даних і покращити роздільність класів.

Посилання Tomek існує, якщо два зразки є найближчими сусідами один одного.

pic

У наведеному нижче коді ми використовуємо sampling_strategy='majority', щоб повторно вибіркувати клас більшості.

Приклад коду:

from imblearn.under_sampling import TomekLinks  

# Застосування Tomek Links  
tomek = TomekLinks(sampling_strategy='majority')  
X_train_tl, y_train_tl = tomek.fit_resample(X_train, y_train)  
# Навчання та оцінка  
model.fit(X_train_tl, y_train_tl)  
y_pred = model.predict(X_test)  
print(classification_report(y_test, y_pred))

b. SMOTE (Техніка синтетичної перевибірки класу меншості)

SMOTE працює, генеруючи синтетичні зразки для класу меншості. Це робиться шляхом:

pic

  1. Вибір випадкового екземпляра класу меншості.
  2. Пошук його k-найближчих сусідів.
  3. Генерація синтетичного екземпляра шляхом інтерполяції між вибраним екземпляром і випадково обраним сусідом.

Приклад коду:

from imblearn.over_sampling import SMOTE  

# Застосування SMOTE  
smote = SMOTE(random_state=42)  
X_train_sm, y_train_sm = smote.fit_resample(X_train, y_train)  
# Навчання моделі  
model.fit(X_train_sm, y_train_sm)  
y_pred = model.predict(X_test)  
print(classification_report(y_test, y_pred))

c. ENN (Редаговані найближчі сусіди)

ENN — це техніка підвибірки, яка видаляє зразки з класу більшості, якщо їхній класовий ярлик відрізняється від класу більшості серед їхніх k-найближчих сусідів. Це допомагає очистити зашумлені точки даних і покращує роздільність класів.

Приклад коду:

from imblearn.under_sampling import EditedNearestNeighbours  

# Застосування ENN  
enn = EditedNearestNeighbours()  
X_train_enn, y_train_enn = enn.fit_resample(X_train, y_train)  
# Навчання моделі  
model.fit(X_train_enn, y_train_enn)  
y_pred = model.predict(X_test)  
print(classification_report(y_test, y_pred))

d. Гібридні методи

Комбінують перевибірку та підвибірку для досягнення кращих результатів.

Приклад: SMOTEENN (Комбінація SMOTE та Редагованих найближчих сусідів)

from imblearn.combine import SMOTEENN  

# Застосування SMOTEENN  
smoteenn = SMOTEENN(random_state=42)  
X_train_smoteenn, y_train_smoteenn = smoteenn.fit_resample(X_train, y_train)  
# Навчання та оцінка  
model.fit(X_train_smoteenn, y_train_smoteenn)  
y_pred = model.predict(X_test)  
print(classification_report(y_test, y_pred))

e. Перевибірка на основі кластерів

Методи на основі кластеризації групують дані в кластери перед перевибіркою, щоб забезпечити різноманітність. Цей метод підвибірки класу більшості заміняє кластер зразків класу більшості на центр кластера алгоритму KMeans. Алгоритм зберігає N зразків більшості, підлаштовуючи алгоритм KMeans під N кластерів для класу більшості та використовуючи координати N центрів кластерів як нові зразки класу більшості.

Приклад: ClusterCentroids

from imblearn.under_sampling import ClusterCentroids  

# Застосування Cluster Centroids  
cc = ClusterCentroids(random_state=42)  
X_train_cc, y_train_cc = cc.fit_resample(X_train, y_train)  
# Навчання та оцінка  
model.fit(X_train_cc, y_train_cc)  
y_pred = model.predict(X_test)  
print(classification_report(y_test, y_pred))

2. Методи на рівні алгоритмів

Ці методи змінюють алгоритми для вирішення проблеми дисбалансу класів.

a. Ваги класів

Ваги класів — це техніка, яку використовують у машинному навчанні для вирішення проблеми дисбалансу класів. Замість того, щоб змінювати набір даних (як перевибірку чи підвибірку), ваги класів змінюють функцію втрат під час навчання. Це змушує модель більше уваги приділяти класу меншості, надаючи йому вищу вагу.
Це досягається шляхом множення втрат, які несе кожен зразок під час навчання, на ваговий коефіцієнт, пов'язаний з його класом.

Приклад: Логістична регресія з вагами класів

from sklearn.linear_model import LogisticRegression  

# Навчання з вагами класів  
model = LogisticRegression(class_weight='balanced', random_state=42)  
model.fit(X_train, y_train)  
# Прогнози  
y_pred = model.predict(X_test)  
print(classification_report(y_test, y_pred))

Приклад: XGBoost з вагами класів

from xgboost import XGBClassifier  

# Навчання XGBoost з scale_pos_weight  
scale_pos_weight = len(y_train[y_train == 0]) / len(y_train[y_train == 1])  
model = XGBClassifier(scale_pos_weight=scale_pos_weight, random_state=42)  
model.fit(X_train, y_train)  

# Прогнози  
y_pred = model.predict(X_test)  
print(classification_report(y_test, y_pred))

Коли використовувати ваги класів:

  • Коли у вас є помірний дисбаланс класів.
  • Коли ви хочете уникнути зміни оригінального набору даних.
  • Коли ефективність обчислень має значення.
  • Як перший крок для вирішення проблеми дисбалансу класів до того, як застосовувати складніші методи.

b. Методи ансамблів

Ансамблеві техніки, такі як Random Forests та Gradient Boosting, можна налаштувати для вирішення проблеми дисбалансу класів.

i. Збалансований Random Forest

Збалансований random forest відрізняється від класичного random forest тим, що він вибирає бутстреп-зразок з класу меншості і вибирає з заміною ту ж кількість зразків з класу більшості.

Приклад:

from imblearn.ensemble import BalancedRandomForestClassifier  

# Навчання Balanced Random Forest  
brf = BalancedRandomForestClassifier(random_state=42)  
brf.fit(X_train, y_train)  
# Прогнози  
y_pred = brf.predict(X_test)  
print(classification_report(y_test, y_pred))

ii. Класифікатор Easy Ensemble

Цей алгоритм відомий як EasyEnsemble. Класифікатор — це ансамбль учнів AdaBoost, навчених на різних збалансованих бутстреп-зразках. Балансування досягається за рахунок випадкової підвибірки.

Приклад:

from imblearn.ensemble import EasyEnsembleClassifier  

# Навчання Easy Ensemble Classifier  
eec = EasyEnsembleClassifier(random_state=42)  
eec.fit(X_train, y_train)  
# Прогнози  
y_pred = eec.predict(X_test)  
print(classification_report(y_test, y_pred))

3. Зміна порогових значень

Регулювання порогу прийняття рішення — це важлива техніка для покращення роботи моделі, особливо коли мова йде про дисбаланс класів. За замовчуванням багато моделей машинного навчання використовують поріг ймовірності 0.5 для бінарної класифікації. Однак це може бути не оптимальним для дисбалансованих наборів даних, оскільки це може призвести до упередженості на користь класу більшості.

Як це працює

  1. Торгівля між точністю та відгуком: Зниження порогу підвищує відгук (чутливість) за рахунок точності, що може бути бажаним у таких сценаріях, як виявлення шахрайства чи медична діагностика.
  2. Індивідуальні пороги: Поріг можна налаштувати для балансування точності та відгуку або для максимізації конкретних метрик, таких як F1-оцінка.

Кроки для налаштування порогів

  1. Навчіть модель і отримайте прогнозовані ймовірності замість класових міток.
  2. Використовуйте криву точність-відгук для візуалізації того, як точність та відгук змінюються з порогом.
  3. Виберіть оптимальний поріг залежно від бажаної метрики (наприклад, максимальна F1-оцінка, конкретна точність чи відгук).

Коли використовувати налаштування порогу

  1. Випадки з високим відгуком: У медичній діагностиці, де пропуск позитивного випадку є дорогим.
  2. Випадки з високою точністю: У детекції спаму, де помилкові позитиви є деструктивними.
    3.
    Збалансовані метрики: Коли важливі такі метрики, як F1-оцінка або подібні.

Приклад коду:

from sklearn.metrics import precision_recall_curve, classification_report  
import numpy as np  

# Прогнозування ймовірностей  
probs = model.predict_proba(X_test)[:, 1]  
# Обчислення кривої точність-відгук  
precision, recall, thresholds = precision_recall_curve(y_test, probs)  
# Знаходимо поріг для максимального F1-скор  
f1_scores = 2 * (precision * recall) / (precision + recall)  
best_threshold = thresholds[np.argmax(f1_scores)]  
# Застосування найкращого порогу  
y_pred_thresholded = (probs >= best_threshold).astype(int)  
print(classification_report(y_test, y_pred_thresholded))

4. Оцінка метрик

Повна залежність від точності може бути оманливою. Використовуйте метрики, які враховують дисбаланс класів:

  • Крива точність-відгук
  • F1-оцінка: Гармонічне середнє точності та відгуку.
  • ROC-AUC: Площа під кривою характеристик прийому-відмови (Receiver Operating Characteristic).

Приклад: Побудова ROC-кривої

from sklearn.metrics import roc_curve, auc  
import matplotlib.pyplot as plt  

# Обчислення ймовірностей  
probs = model.predict_proba(X_test)[:, 1]  
fpr, tpr, _ = roc_curve(y_test, probs)  
roc_auc = auc(fpr, tpr)  
# Побудова графіку  
plt.figure()  
plt.plot(fpr, tpr, color='darkorange', lw=2, label='ROC крива (площа = %0.2f)' % roc_auc)  
plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')  
plt.xlabel('Частка хибнопозитивних')  
plt.ylabel('Частка хибно відхилених')  
plt.title('Характеристики прийому-відмови')  
plt.legend(loc="lower right")  
plt.show()

Реальні приклади застосування

  1. Виявлення шахрайства: Шахрайські транзакції рідкісні, але їх важливо виявляти.
  2. Медична діагностика: Виявлення рідкісних захворювань або станів.
  3. Прогнозування відтоку клієнтів: Прогнозування відтоку клієнтів у підписних бізнесах.

Висновок

Дисбаланс класів — це поширена проблема в машинному навчанні, але з правильними методами її можна ефективно вирішити. Поєднуючи методи на рівні даних і алгоритмів та використовуючи відповідні метрики оцінки, ви можете створювати надійні моделі, які добре працюють як для класів меншості, так і більшості.

Пам'ятайте, що вибір техніки залежить від проблеми, набору даних та бізнес-вимог. Почніть з вивчення ваших даних, зрозумійте дисбаланс і намагайтеся знайти найкраще рішення для вашого випадку.

Перекладено з: How to Handle Class Imbalance in Machine Learning

Leave a Reply

Your email address will not be published. Required fields are marked *