Условие
Фича 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.
Подводные камни
- One-hot на 50k → 50k столбцов × n rows: память и time взрывается. Для tree-based модели бесполезно — будут только бинарные splits.
- Cold start: новые merchants на проде не видены — embedding не обучен. Fallback на
<UNK>token. - Hashing collision: 50k → 128 bins, в среднем 400 merchants на bin. Коллизии съедают сигнал. Решение: больший n_bins (4096+).
- Target encoding на rare (n_c < 5) → noise. Всегда smoothing.
- 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.