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

Как будешь решать проблему неравномерного распределения данных?

2.0 Middle🔥 151 комментариев
#Машинное обучение

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

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

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

Решение проблемы неравномерного распределения данных (Imbalanced Data)

Неравномерное распределение (дисбаланс классов) одна из самых распространенных проблем в machine learning. Это когда один класс существенно преобладает над другими, что приводит к смещению модели в сторону мажоритарного класса.

Диагностика проблемы

Сначала нужно оценить степень дисбаланса:

import pandas as pd
from sklearn.utils import class_weight

# Проверяем распределение классов
print(y_train.value_counts())
print(y_train.value_counts(normalize=True))

# Пример: 95% класс 0, 5% класс 1 (серьёзный дисбаланс)
# 0    9500
# 1     500

Стратегии решения

1. Взвешивание классов (Class Weights)

Это самый простой и часто эффективный способ. Модель штрафуется больше за ошибки на меньшинстве:

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

# Автоматический расчёт весов
class_weights = compute_class_weight(
    class_weight=balanced,
    classes=np.unique(y_train),
    y=y_train
)

# Использование с Random Forest
model = RandomForestClassifier(
    class_weight=balanced,  # или dict с явными весами
    random_state=42
)
model.fit(X_train, y_train)

# С логистической регрессией
from sklearn.linear_model import LogisticRegression

model = LogisticRegression(class_weight=balanced)
model.fit(X_train, y_train)

# С нейросетью
import tensorflow as tf

class_weights = {0: 1.0, 1: 19.0}  # Класс 1 в 19 раз менее частый

model.fit(X_train, y_train, 
          class_weight=class_weights,
          epochs=10)

2. Передискретизация (Resampling)

Модифицируем обучающий набор данных. Есть два подхода:

Oversampling (увеличение меньшинства):

from imblearn.over_sampling import RandomOverSampler, SMOTE

# Простой случайный oversampling
over_sampler = RandomOverSampler(random_state=42)
X_resampled, y_resampled = over_sampler.fit_resample(X_train, y_train)

# SMOTE (Synthetic Minority Over-sampling Technique) - создаёт синтетические примеры
smote = SMOTE(random_state=42, k_neighbors=5)
X_resampled, y_resampled = smote.fit_resample(X_train, y_train)

model = RandomForestClassifier()
model.fit(X_resampled, y_resampled)

Undersampling (уменьшение большинства):

from imblearn.under_sampling import RandomUnderSampler

under_sampler = RandomUnderSampler(random_state=42)
X_resampled, y_resampled = under_sampler.fit_resample(X_train, y_train)

model = RandomForestClassifier()
model.fit(X_resampled, y_resampled)

Комбинированный подход (SMOTE + Tomek Links):

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

pipeline = Pipeline([
    (smote, SMOTE(random_state=42)),
    (tomek, TomekLinks()),
    (clf, RandomForestClassifier())
])

pipeline.fit(X_train, y_train)

3. Выбор правильных метрик оценки

Для дисбалансированных данных accuracy НЕПРАВИЛЬНАЯ метрика. Используй:

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

# Плохо: accuracy не отражает качество
accuracy = (TP + TN) / (TP + TN + FP + FN)
# На дисбалансе может быть 95%, если просто предсказывать мажоритарный класс

# Хорошо: F1-score сбалансирован
f1 = model.score(X_test, y_test, scoring=f1)

# Хорошо: ROC-AUC не зависит от баланса
roc_auc = roc_auc_score(y_test, y_pred_proba)

# Хорошо: Precision и Recall
from sklearn.metrics import precision_score, recall_score
precision = precision_score(y_test, y_pred)
recall = recall_score(y_test, y_pred)

# Хорошо: Balanced Accuracy
balanced_acc = balanced_accuracy_score(y_test, y_pred)

4. Пороги классификации (Threshold Tuning)

По умолчанию порог = 0.5. Для дисбалансированных данных его можно изменить:

from sklearn.metrics import precision_recall_curve

# Получаем вероятности
y_pred_proba = model.predict_proba(X_test)[:, 1]

# Находим оптимальный порог
precision, recall, thresholds = precision_recall_curve(y_test, y_pred_proba)

# Пороги, балансирующие precision и recall
f1_scores = 2 * (precision * recall) / (precision + recall + 1e-10)
best_threshold = thresholds[np.argmax(f1_scores[:-1])]

# Используем новый порог
y_pred = (y_pred_proba > best_threshold).astype(int)

5. Использование ensemble методов

Некоторые методы более устойчивы к дисбалансу:

from imblearn.ensemble import (
    BalancedRandomForestClassifier,
    EasyEnsembleClassifier
)

# Специальный Random Forest для дисбалансированных данных
model = BalancedRandomForestClassifier(
    n_estimators=100,
    random_state=42
)
model.fit(X_train, y_train)

# EasyEnsemble комбинирует undersampling с ensemble
model = EasyEnsembleClassifier(
    n_estimators=10,
    random_state=42
)
model.fit(X_train, y_train)

Сравнительная таблица методов

МетодСкоростьЭффективностьКогда использовать
Class weightsБыстроХорошаяПервый выбор, простые модели
SMOTEСреднеОтличнаяУмеренный дисбаланс (1:10)
UndersamplingБыстроХорошаяМного данных, сильный дисбаланс
Threshold tuningБыстроХорошаяУже есть обученная модель
Balanced ensembleСреднеОтличнаяЭкстремальный дисбаланс (1:1000)

Рекомендуемый pipeline

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from imblearn.pipeline import Pipeline as ImbPipeline
from imblearn.over_sampling import SMOTE

# Правильный pipeline для дисбалансированных данных
pipeline = ImbPipeline([
    (scaler, StandardScaler()),
    (smote, SMOTE(random_state=42)),
    (model, RandomForestClassifier(class_weight=balanced))
])

pipeline.fit(X_train, y_train)

# Оценка на валидационном наборе
from sklearn.model_selection import cross_val_score
scores = cross_val_score(
    pipeline, X_train, y_train,
    scoring=roc_auc,  # Используем ROC-AUC вместо accuracy
    cv=5
)

В 90% случаев комбинация class weights + SMOTE + правильные метрики решает проблему дисбаланса.

Как будешь решать проблему неравномерного распределения данных? | PrepBro