← Назад к вопросам

Что такое дисбаланс классов?

1.7 Middle🔥 241 комментариев
#Машинное обучение#Метрики и оценка моделей

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Class Imbalance (дисбаланс классов)

Class imbalance — это ситуация, когда количество образцов одного класса значительно превышает количество образцов другого класса в датасете.

Примеры

import numpy as np

# Пример: Fraud detection (мошенничество)
total_transactions = 10000
fraudulent = 50  # 0.5%
legitimate = 9950  # 99.5%

ratio = fraudulent / legitimate
print(f"Imbalance ratio: 1:{int(legitimate/fraudulent)}")  # 1:199

# Пример: Disease detection
diseased = 100  # 10%
healthy = 900   # 90%
print(f"Imbalance ratio: 1:{int(healthy/diseased)}")  # 1:9

# Пример: Extremely imbalanced (очень неуравновешенный)
rare_event = 1
common_event = 99999
print(f"Imbalance ratio: 1:{int(common_event/rare_event)}")  # 1:99999

Проблема: Accuracy парадокс

from sklearn.metrics import accuracy_score, precision_score, recall_score
from sklearn.linear_model import LogisticRegression
import numpy as np

# Данные: 95% класс 0, 5% класс 1
y_true = np.array([0]*95 + [1]*5)
y_pred_lazy = np.array([0]*100)  # модель всегда предсказывает класс 0

accuracy = accuracy_score(y_true, y_pred_lazy)
precision = precision_score(y_true, y_pred_lazy, zero_division=0)
recall = recall_score(y_true, y_pred_lazy, zero_division=0)

print(f"Accuracy: {accuracy:.2%}")    # 95% (высокий!)
print(f"Precision: {precision:.2%}")  # 0% (класс 1 не предсказан)
print(f"Recall: {recall:.2%}")        # 0% (класс 1 не предсказан)

# Модель бесполезна, но accuracy выглядит хорошо!

Почему это проблема

1. Accuracy не отражает качество
   → модель может быть бесполезной, но иметь 95%+ accuracy

2. Модель смещена к majority классу
   → учится предсказывать только frequent класс

3. Неправильная оценка performance
   → нужны другие метрики

Правильные метрики для imbalanced данных

from sklearn.metrics import (
    confusion_matrix, precision_recall_curve, roc_auc_score,
    f1_score, roc_curve
)

y_true = np.array([0]*95 + [1]*5)
y_proba = np.random.random(100)

# НЕПРАВИЛЬНО (не использовать)
accuracy = accuracy_score(y_true, y_proba > 0.5)

# ПРАВИЛЬНО (используй эти метрики)

# 1. F1-score (balance между precision и recall)
f1 = f1_score(y_true, y_proba > 0.5)
print(f"F1: {f1:.3f}")

# 2. Precision-Recall curve (вместо ROC)
precision, recall, _ = precision_recall_curve(y_true, y_proba)
print(f"Precision-Recall AUC: {np.trapz(precision, recall):.3f}")

# 3. ROC-AUC (работает лучше, чем accuracy)
roc_auc = roc_auc_score(y_true, y_proba)
print(f"ROC-AUC: {roc_auc:.3f}")

# 4. Confusion matrix
tn, fp, fn, tp = confusion_matrix(y_true, y_proba > 0.5).ravel()
print(f"TP: {tp}, FN: {fn}, FP: {fp}, TN: {tn}")

Методы борьбы с дисбалансом

1. Oversampling (увеличение minority класса)

from imblearn.over_sampling import RandomOverSampler, SMOTE
from imblearn.pipeline import Pipeline

X_train = np.array([[1, 2], [2, 3], [3, 4], [4, 5]])
y_train = np.array([0, 0, 0, 1])  # дисбаланс

# Random oversampling (просто дублируем minority)
ros = RandomOverSampler(random_state=42)
X_resampled, y_resampled = ros.fit_resample(X_train, y_train)
print(f"Original: {len(y_train)}, Resampled: {len(y_resampled)}")

# SMOTE: синтетические образцы
smote = SMOTE(random_state=42)
X_smote, y_smote = smote.fit_resample(X_train, y_train)

2. Undersampling (уменьшение majority класса)

from imblearn.under_sampling import RandomUnderSampler

rus = RandomUnderSampler(random_state=42)
X_resampled, y_resampled = rus.fit_resample(X_train, y_train)
print(f"Original: {len(y_train)}, Resampled: {len(y_resampled)}")

# Минус: теряем информацию

3. Weighted loss (взвешивание классов)

from sklearn.utils.class_weight import compute_class_weight
from sklearn.ensemble import RandomForestClassifier

# Вычисляем веса
class_weights = compute_class_weight(
    'balanced',
    classes=np.unique(y_train),
    y=y_train
)
print(f"Class weights: {class_weights}")

# Используем в модели
model = RandomForestClassifier(
    class_weight='balanced'  # даёт больший вес minority
)
model.fit(X_train, y_train)

# Или вручную указать веса
model = RandomForestClassifier(
    class_weight={0: 1, 1: 10}  # класс 1 в 10 раз важнее
)

4. Hybrid: SMOTE + ENN (Edited Nearest Neighbors)

from imblearn.pipeline import Pipeline
from imblearn.over_sampling import SMOTE
from imblearn.under_sampling import EditedNearestNeighbours

pipeline = Pipeline([
    ('smote', SMOTE(random_state=42)),
    ('enn', EditedNearestNeighbours()),
])

X_resampled, y_resampled = pipeline.fit_resample(X_train, y_train)

Практический пример: Fraud Detection

import pandas as pd
from sklearn.model_selection import train_test_split
from xgboost import XGBClassifier
from sklearn.metrics import roc_auc_score, f1_score
from imblearn.over_sampling import SMOTE

# Данные
X = pd.DataFrame(np.random.randn(10000, 10))
y = np.array([0]*9950 + [1]*50)  # 0.5% fraud

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

# SMOTE на тренировочных данных
smote = SMOTE(random_state=42)
X_train_smoted, y_train_smoted = smote.fit_resample(X_train, y_train)

print(f"Before SMOTE: {len(y_train)}")
print(f"After SMOTE: {len(y_train_smoted)}")
print(f"Class balance: {np.mean(y_train_smoted):.2%}")  # 50%

# Обучение на сбалансированных данных
model = XGBClassifier(
    scale_pos_weight=(y_train == 0).sum() / (y_train == 1).sum(),
    random_state=42
)
model.fit(X_train_smoted, y_train_smoted)

# Оценка на оригинальном тестовом наборе
y_pred_proba = model.predict_proba(X_test)[:, 1]

roc_auc = roc_auc_score(y_test, y_pred_proba)
f1 = f1_score(y_test, y_pred_proba > 0.5)

print(f"ROC-AUC: {roc_auc:.3f}")
print(f"F1-score: {f1:.3f}")

Checklist для imbalanced данных

✓ Используй stratified k-fold для кросс-валидации
✓ Применяй SMOTE или weighted loss
✓ Выбирай F1, Precision-Recall, ROC-AUC (не Accuracy)
✓ Визуализируй confusion matrix
✓ Проверяй recall и precision для каждого класса
✓ Тестируй на оригинальном (imbalanced) тестовом наборе
✓ Не забывай про бизнес-контекст (cost of FP vs FN)

Резюме

Class Imbalance:

  • Minority класс сильно недопредставлен
  • Accuracy парадокс: высокая accuracy при бесполезной модели
  • Методы: SMOTE, weighted loss, stratified CV
  • Метрики: F1, ROC-AUC, Precision-Recall (не Accuracy)
  • Всегда тестируй на оригинальных (imbalanced) данных
Что такое дисбаланс классов? | PrepBro