Собесов

Сценарий ML: class_weight в sklearn и эквиваленты

ML / Data ScienceКласс дисбалансЛёгкаяMiddle

Условие

Объясните, что делает class_weight='balanced' в sklearn, как это математически.

Решение

Подход

class_weight='balanced' устанавливает w_c = n_total / (K · n_c), где K — число классов. Самый редкий класс получает наибольший вес. Каждый пример классa c вносит в loss w_c · L(y_i, ŷ_i) вместо обычного L.

Эквивалентно oversampling без действительного дублирования данных.

Реализация

from sklearn.linear_model import LogisticRegression
from sklearn.utils.class_weight import compute_class_weight
import numpy as np
 
# auto-balanced
clf = LogisticRegression(class_weight='balanced').fit(X, y)
 
# вручную
classes = np.unique(y)
weights = compute_class_weight('balanced', classes=classes, y=y)
weight_dict = dict(zip(classes, weights))
# Например: {0: 0.51, 1: 33.3} для 99.7%/0.3%
clf = LogisticRegression(class_weight=weight_dict)

Эквиваленты в библиотеках

# XGBoost (бинарка)
import xgboost as xgb
scale_pos_weight = (y==0).sum() / (y==1).sum()  # ~333
xgb.XGBClassifier(scale_pos_weight=scale_pos_weight)
 
# LightGBM
import lightgbm as lgb
lgb.LGBMClassifier(class_weight='balanced')
# или is_unbalance=True
 
# CatBoost
from catboost import CatBoostClassifier
CatBoostClassifier(auto_class_weights='Balanced')
 
# PyTorch
import torch.nn as nn
weights = torch.tensor([1.0, 333.0])
criterion = nn.CrossEntropyLoss(weight=weights)

Sample weight vs class weight

  • class_weight: вес одинаков для всех экземпляров класса.
  • sample_weight: индивидуальный вес каждой строки. Гибче (можно учитывать recency, importance).
sample_w = np.where(y==1, 100, 1) * recency_weight  # сочетаем
clf.fit(X, y, sample_weight=sample_w)

Сравнение с oversampling

class_weight Oversampling SMOTE
Память O(n) O(K·n) O(K·n)
Train time Тот же Дольше Дольше
Калибровка Раbias predict_proba Bias proba Bias proba
Variance reduction Нет Да (точные дубли увеличивают шум) Чуть лучше дублирования

class_weight обычно — first choice для tree-based / linear; почти бесплатно и эффективно.

Подводные камни

  1. Predict_proba становится mis-calibrated: модель predicts «balanced» probabilities, не population priors. Калибровать после.
  2. С threshold по умолчанию 0.5: после class_weight модель predicts много positives. Думайте через threshold, не «balanced» означает «лучше».
  3. На очень severe imbalance (1:10000+) class_weight может не помочь; нужно сочетание с focal loss или undersampling.
  4. На multilabel или multiclass с rare class — взвешивание тоже помогает, но осторожно с micro vs macro метриками.
  5. class_weight='balanced_subsample' для RF — пересчёт весов на каждом bootstrap, не на полном dataset.

Эталонный ответ

class_weight='balanced' устанавливает w_c = n_total/(K·n_c), умножая loss на вес класса. Эквивалент oversampling без дублирования. Эквиваленты: scale_pos_weight (XGB), class_weight (LGBM), weight в CrossEntropyLoss (torch). Predict_proba становится biased — нужна калибровка.

Хочешь увидеть разбор?

Зарегистрируйся бесплатно — откроется развёрнутое решение этой задачи и ещё 4 на выбор.

Зарегистрироваться и увидеть разбор
Уже есть аккаунт? Войти