Методы и стратегии улучшения производительности модели на несбалансированных наборах данных

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

Где это происходит?

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

Одной из классических демонстраций дисбаланса классов является использование набора данных creditcard.csv из Kaggle, который представляет собой сильно несбалансированный набор данных, содержащий транзакции по кредитным картам с целевой переменной, указывающей, является ли транзакция мошеннической или нет.

import pandas as pd
from sklearn.model_selection import train_test_split

df = pd.read_csv('creditcard.csv')
df.head()
X = df.drop('Class',axis=1)
y = df['Class']

import matplotlib.pyplot as plt
import numpy as np

unique, counts = np.unique(y, return_counts=True)
plt.bar(unique, counts)
plt.xticks([0, 1], ['Non-Fraudulent', 'Fraudulent'])
plt.ylabel('Number of Instances')
plt.show()

print('Number of non-fraudulent transactions:', counts[0])
print('Number of fraudulent transactions:', counts[1])
print('The ratio of fraudulent transactions: %', 100 * (counts[1] / (counts[0]+counts[1])))

"""
Number of non-fraudulent transactions: 284315
Number of fraudulent transactions: 492
The ratio of fraudulent transactions: % 0.1727485630620034
"""

Эффект дисбаланса классов

Это оказывает значительное влияние на производительность моделей машинного обучения. Модели, обученные на таких данных, имеют тенденцию быть смещенными в сторону класса большинства. Это связано с тем, что модели пытаются свести к минимуму общую частоту ошибок и при этом игнорируют класс меньшинства. В результате модели хорошо предсказывают класс большинства, но плохо работают с классом меньшинства.

Регуляризация важна. Если модель не регуляризована должным образом, она может перекрыть класс большинства, что приведет к плохому обобщению новых данных. Техники аугментации данных, о которых я вскоре расскажу, в этом плане тоже не помогут. Эти методы иногда могут приводить к переоснащению, поскольку они увеличивают шансы воспроизведения одних и тех же данных и могут привести к тому, что модель запоминает обучающие данные, а не изучает лежащие в их основе закономерности.

Как это оценить?

Модели, обученные на несбалансированных данных, могут иметь высокий показатель точности, но нам следует избегать его использования. Точность может ввести в заблуждение при работе с несбалансированными наборами данных. Потому что точность измеряет общий процент правильных прогнозов, независимо от распределения классов.

from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, confusion_matrix

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

lr = LogisticRegression()
lr.fit(X_train, y_train)
y_pred = lr.predict(X_test)

print('Accuracy:', accuracy_score(y_test, y_pred)) 
# Accuracy: 0.9986306660580738

Эта точность кажется большой, но вместо разработки модели, если мы скажем, что каждое наблюдение в тесте не является мошенничеством, мы все равно получим 99,82-процентный успех. Так что на модель особо не надеешься.

Вместо точности мы можем использовать некоторые метрики для оценки:

  • Матрица путаницы — полезный инструмент для понимания того, как модель работает в каждом классе.
print(confusion_matrix(y_test, y_pred))

"""
[[56829    35]
 [   43    55]]
"""

Если мы посмотрим на матрицу путаницы, то увидим, что модель почти всегда правильно предсказывает класс большинства (немошеннические транзакции), но довольно часто неправильно классифицирует класс меньшинства (мошеннические транзакции), только в 55 из 98 случаев. быть правильно идентифицированы как мошеннические. Это означает, что модель неэффективна при выявлении интересующих случаев (мошеннических сделок) и смещена в сторону мажоритарного класса.

  • Мы можем использовать точность и отзыв. Точность — это доля истинных положительных результатов среди предсказанных положительных случаев, а полнота — это доля истинных положительных результатов среди фактических положительных случаев.
from sklearn.metrics import precision_score, recall_score

precision = precision_score(y_test, y_pred)
recall = recall_score(y_test, y_pred)

print('Precision:', precision)
print('Recall:', recall)

"""
Precision: 0.6111111111111112
Recall: 0.5612244897959183
"""

Как мы видим, показатель точности относительно высок, но показатель отзыва ниже, что указывает на то, что модель плохо выявляет положительные случаи (мошеннические транзакции). Модель будет делать меньше ложноположительных прогнозов (т. е. прогнозировать, что транзакция является мошеннической, когда это не так), но она также будет выявлять меньше реальных мошеннических транзакций.

  • Кривая ROC и показатель AUC являются полезными показателями для оценки общей производительности модели и сравнения различных моделей.
from sklearn.metrics import roc_curve, auc

y_pred_prob = lr.predict_proba(X_test)[:, 1]  # Probability estimates of the positive class
fpr, tpr, thresholds = roc_curve(y_test, y_pred_prob)
roc_auc = auc(fpr, tpr)

# ROC curve
plt.figure(figsize=(8, 6))
plt.plot(fpr, tpr, color='darkorange', lw=2, label='ROC curve (AUC = %0.2f)' % roc_auc)
plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver operating characteristic (ROC) curve')
plt.legend(loc="lower right")
plt.show()

print('AUC score:', roc_auc)

  • Сбалансированная точность — это метрика, которая учитывает дисбаланс классов путем усреднения оценки отзыва каждого класса.
from sklearn.metrics import balanced_accuracy_score

y_pred = lr.predict(X_test)
balanced_acc = balanced_accuracy_score(y_test, y_pred)

print('Balanced accuracy:', balanced_acc)
# Balanced accuracy: 0.7803044930690339

Как вы можете заметить, точность балансировки намного меньше обычной точности. Следовательно, это лучшая метрика для оценки модели в случае дисбаланса.

  • Коэффициент корреляции Мэтьюса — это еще одна метрика, которая учитывает истинно положительные, истинно отрицательные, ложноположительные и ложноотрицательные значения в матрице путаницы. Обычно он считается сбалансированным показателем, который можно использовать, даже если классы очень разного размера.
from sklearn.metrics import matthews_corrcoef

y_pred = lr.predict(X_test)
mcc = matthews_corrcoef(y_test, y_pred)

print('Matthews Correlation Coefficient:', mcc)
# Matthews Correlation Coefficient: 0.5849534280814107

Как справиться с дисбалансом классов?

Обработка дисбаланса классов может повысить производительность и надежность моделей машинного обучения, а также обеспечить их хорошее обобщение для новых данных. Это также может привести к более точным и значимым показателям оценки, которые отражают реальную производительность модели в каждом классе.

Существует множество способов справиться с дисбалансом классов.

  • Неполная выборка
  • Передискретизация (SMOTE)
  • Метод ансамбля
  • Вес класса
  • Очаговая потеря

Мы можем использовать библиотеку imbalanced-learn для обработки различных методов. Вы можете добраться до документации здесь. Установить:

pip install imbalanced-learn

Эти методы следует применять только к обучающим данным, а результирующую модель следует оценивать на исходных тестовых данных.

Неполная выборка

Мы уменьшаем количество выборок из мажоритарного класса, чтобы сбалансировать распределение классов в обучающих данных.

Это простая техника, и, поскольку мы уменьшаем размер данных, которые мы вводим в модели, мы сокращаем время обучения и требования к памяти.

С другой стороны, выбрасывание данных означает, что мы теряем информацию. Это может снизить общую производительность модели и качество обобщения.

Мы можем использовать недостаточную выборку, если данные (особенно класс большинства) содержат много избыточных выборок, которые не предоставляют много дополнительной информации для модели, и когда сложно или дорого собрать больше выборок из класса меньшинства. Кроме того, мы можем использовать его, если разрыв между классами не такой большой. Мы можем немного настроить его, удалив некоторые сэмплы из мажоритарного класса.

from imblearn.under_sampling import RandomUnderSampler

# undersample
rus = RandomUnderSampler(random_state=42)
X_train_resampled, y_train_resampled = rus.fit_resample(X_train, y_train)

# plot the new distribution
unique, counts = np.unique(y_train_resampled, return_counts=True)
plt.bar(unique, counts)
plt.xticks([0, 1], ['Non-Fraudulent', 'Fraudulent'])
plt.ylabel('Number of Instances')
plt.show()

lr = LogisticRegression()
lr.fit(X_train_resampled, y_train_resampled)
y_pred = lr.predict(X_test)

print('Accuracy:', accuracy_score(y_test, y_pred))
print('Confusion matrix:')
print(confusion_matrix(y_test, y_pred))
precision = precision_score(y_test, y_pred)
recall = recall_score(y_test, y_pred)

print('Precision:', precision)
print('Recall:', recall)

"""
Accuracy: 0.9501597556265581
Confusion matrix:
[[54033  2831]
 [    8    90]]
Precision: 0.030811365970558027
Recall: 0.9183673469387755
"""

Как вы можете заметить, мы значительно улучшили Отзыв, но ради этого пожертвовали Точностью.

Передискретизация (SMOTE)

В отличие от недостаточной выборки, теперь мы создаем больше дубликатов класса меньшинства. Существуют различные способы передискретизации, но самый известный из них называется синтетическим методом передискретизации меньшинства (SMOTE).

SMOTE генерирует синтетические выборки для класса меньшинства путем интерполяции новых точек между существующими. Для каждой выборки в классе меньшинства он выбирает k ближайших соседей из того же класса. Затем он случайным образом выбирает одного из этих k соседей и вычисляет разницу между вектором признаков исходной выборки и выбранным соседом. Он умножает эту разницу на случайное число от 0 до 1 и добавляет его к вектору признаков исходного образца.

Когда мы используем Smote, мы не теряем информацию, так как этот метод не удаляет сэмпл. Это снижает риск переобучения, поскольку генерирует синтетические образцы, не идентичные исходным образцам.

С другой стороны, SMOTE генерирует синтетические выборки, которые могут привносить шум и выбросы в данные. Если набор данных большой, то применение SMOTE может быть дорогостоящим.

SMOTE особенно полезен, когда классовый дисбаланс серьезен, а класс меньшинства значительно недопредставлен. Это также полезно, когда для класса меньшинства доступны ограниченные данные, поскольку он может создавать дополнительные синтетические образцы для улучшения производительности модели.

from imblearn.over_sampling import SMOTE
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report
lr = LogisticRegression()
lr.fit(X_train, y_train)
y_pred = lr.predict(X_test)
print('Classification report:\n', classification_report(y_test, y_pred))

# Apply SMOTE oversampling to the training data
sm = SMOTE(random_state=42)
X_train_resampled, y_train_resampled = sm.fit_resample(X_train, y_train)

lr = LogisticRegression()
lr.fit(X_train_resampled, y_train_resampled)
y_pred = lr.predict(X_test)

# Evaluate the performance of the model on the resampled test data
print('SMOTE Classification report:\n', classification_report(y_test, y_pred))

Опять же, мы улучшили память.

Метод ансамбля

Методы ансамбля могут использоваться для повышения точности классификации классов меньшинств.

Эти методы могут улучшить производительность модели за счет уменьшения переобучения и повышения точности. И они могут обрабатывать несбалансированные данные, придавая больший вес классам меньшинств.

Использование метода ансамбля может быть дорогостоящим и трудным для интерпретации.

from imblearn.ensemble import BalancedRandomForestClassifier

model = BalancedRandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)

print('Classification report:\n', classification_report(y_test, y_pred))

Вес класса

В этом методе алгоритм машинного обучения присваивает каждому классу в обучающих данных разные веса, так что модель наказывается больше за неправильную классификацию класса меньшинства, чем класса большинства.

Преимущество взвешивания классов заключается в том, что это простой и эффективный метод, который можно использовать с большинством алгоритмов машинного обучения. Это также может быть полезно, когда дисбаланс классов не слишком велик.

Одним из недостатков взвешивания классов является то, что оно может быть неэффективным при очень серьезном дисбалансе классов, поскольку модель все еще может быть смещена в сторону класса большинства. Другим недостатком является то, что поиск правильного веса для каждого класса может быть трудным и может потребовать некоторых экспериментов.

from sklearn.utils.class_weight import compute_class_weight

class_weights = compute_class_weight(
                                        class_weight = "balanced",
                                        classes = np.unique(y_train),
                                        y = y_train                                                    
                                    )
class_weights = dict(zip(np.unique(y_train), class_weights))

# Train a logistic regression model with class weighting
model = LogisticRegression(class_weight=class_weights)
model.fit(X_train, y_train)

# Make predictions on the test set
y_pred = model.predict(X_test)

# Print classification report
print(classification_report(y_test, y_pred))

Очаговая потеря

Focal Loss — это функция потерь, предназначенная для решения проблем дисбаланса классов в моделях машинного обучения. Он был представлен в статье Лина под названием Потери фокуса для обнаружения плотных объектов. Идея Focal Loss состоит в том, чтобы придать больший вес сложным примерам (т. е. образцам, которые ошибочно классифицированы с высокой достоверностью), чем простым примерам. Это помогает модели больше сосредоточиться на сложных примерах и повысить эффективность работы с классом меньшинства.

Focal Loss можно использовать в задачах обнаружения объектов, где количество экземпляров объекта намного меньше, чем экземпляров фона. Его можно использовать в других задачах классификации, где проблемой является дисбаланс классов.

Мы можем использовать Библиотеку Focal Loss.

pip install focal-loss

import tensorflow as tf
from tensorflow.keras.layers import Dense, Input
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.callbacks import EarlyStopping
from focal_loss import BinaryFocalLoss

input_shape = (X_train.shape[1],)

# the model architecture
input_layer = Input(shape=input_shape)
hidden_layer = Dense(64, activation='relu')(input_layer)
output_layer = Dense(1, activation='sigmoid')(hidden_layer)
model = Model(inputs=input_layer, outputs=output_layer)

# Focal Loss function
focal_loss = BinaryFocalLoss(gamma=2)

# Compile the model
model.compile(loss=focal_loss, optimizer=Adam(lr=0.001), metrics=['accuracy'])
early_stopping = EarlyStopping(patience=3, restore_best_weights=True)
history = model.fit(X_train, y_train, validation_split=0.2, epochs=10, batch_size=32, callbacks=[early_stopping])

# Evaluate the model on the testing data
loss, accuracy = model.evaluate(X_test, y_test)

Заключение

В этом посте мы обсудили проблему дисбаланса классов в машинном обучении и рассмотрели различные методы его решения. Мы начали с определения того, что такое дисбаланс классов и почему важно с ним справляться. Затем мы обсудили наиболее распространенные методы устранения дисбаланса классов. Для каждой техники мы обсудили ее преимущества и недостатки. Мы также применили некоторые из этих методов к набору данных о мошенничестве с кредитными картами и сравнили их эффективность.

Читать далее













Источники

https://www.youtube.com/watch?v=6DCDxqoRxHQ&t=665s

https://www.youtube.com/watch?v=JnlM4yLFNuo

https://www.youtube.com/watch?v=L7Xj9dRfSKk

СТАНЬТЕ ПИСАТЕЛЕМ на MLearning.ai