Собесов

Сценарий ML: high-cardinality categorical encoding

ML / Data ScienceFeature engineeringСредняяSenior

Условие

Фича merchant_id с 50 000 уникальных значений. Как энкодировать?

Решение

Подход

One-hot для 50k — взрыв размерности (50k столбцов, плотность 0.00002). Альтернативы:

Метод Когда Минусы
Target encoding Линейные модели, GBDT Leakage риск
Frequency encoding Простой baseline Слабая дифференциация
Hashing trick Линейные модели, online Коллизии
Learned embeddings Neural networks Нужны данные
Grouping (top-K + other) GBDT Теряем хвост
LeaveOneOut encoding GBDT Похоже на target enc
WoE / IV LogReg в кредитном скоринге Только для binary y

Реализация

import pandas as pd
import numpy as np
 
# 1. Frequency encoding
freq = X['merchant'].value_counts()
X['merchant_freq'] = X['merchant'].map(freq)
 
# 2. Hashing trick
from sklearn.feature_extraction import FeatureHasher
hasher = FeatureHasher(n_features=128, input_type='string')
X_hash = hasher.transform(X['merchant'].astype(str).values.reshape(-1,1))
 
# 3. Grouping: топ-200, остальное в 'other'
top_k = X['merchant'].value_counts().head(200).index
X['merchant_grouped'] = X['merchant'].where(X['merchant'].isin(top_k), 'other')
 
# 4. Embedding в torch
import torch.nn as nn
emb_dim = min(50, len(unique)//2 + 1)
emb = nn.Embedding(num_embeddings=50_001, embedding_dim=emb_dim, padding_idx=0)
# learnable во время обучения end-to-end

Правило большого пальца

  • n_unique < 10: one-hot, без вопросов.
  • 10 < n < 100: one-hot или ordinal (если ordinal).
  • 100 < n < 10k: target encoding с smoothing.
  • n > 10k: hashing или embeddings или grouping top-K.

Embedding dimensionality

Эвристика: emb_dim = min(50, n_unique // 2) (Howard, fastai) или emb_dim = n_unique^0.25 (Google).

Combining

Часто работает: top-K one-hot + target_encoded остальное + frequency.

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

  1. One-hot на 50k → 50k столбцов × n rows: память и time взрывается. Для tree-based модели бесполезно — будут только бинарные splits.
  2. Cold start: новые merchants на проде не видены — embedding не обучен. Fallback на <UNK> token.
  3. Hashing collision: 50k → 128 bins, в среднем 400 merchants на bin. Коллизии съедают сигнал. Решение: больший n_bins (4096+).
  4. Target encoding на rare (n_c < 5) → noise. Всегда smoothing.
  5. Drift cardinality: на проде через год 200k merchants. Регулярный refit / re-grouping.

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

High-cardinality (>10k): target encoding с smoothing, hashing (для линейных/online), learned embeddings (для neural), grouping top-K + other (для GBDT). One-hot не подходит. Cold-start через <UNK>. Регулярный refit при drift cardinality.

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

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

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