Условие
Спроектируйте систему ранжирования для продукта Intuit (например, ранжирование подсказок-категорий расходов в TurboTax). Опишите: бизнес-цель, метрики, признаки, модель, обучение и оценку.
Решение
Подход (фреймворк ML system design)
1. Бизнес-цель и метрики.
- Бизнес: уменьшить ручной ввод, ускорить заполнение декларации → больше completed returns.
- Online-метрики: средняя позиция выбранной подсказки, время заполнения, отказ от подсказок.
- Offline-метрики: NDCG@k, MRR, MAP@k.
2. Формулировка задачи.
- Pointwise (regression / classification «кликнет/нет») — простая, но игнорирует относительный порядок.
- Pairwise (RankNet, LambdaRank) — учится сравнению пар.
- Listwise (LambdaMART, ListNet) — оптимизирует метрику ранжирования напрямую. Чаще всего побеждает.
3. Признаки.
- Контекст пользователя: история выбранных категорий, регион, тип бизнеса.
- Признаки кандидата (категории): глобальная популярность, частота для похожих пользователей, эмбеддинг от описания.
- Взаимодействие пользователь × кандидат: cosine similarity эмбеддингов, co-occurrence в исторических декларациях.
4. Модель.
- Бейзлайн: популярность категории (по этому юзеру / глобально). Закроет ~30% задачи.
- Основная модель: LambdaMART (LightGBM с
objective='lambdarank'). - Расширение: two-tower neural retrieval + LambdaMART как re-ranker.
5. Данные и обучение.
- Логи:
(user, query_context, candidate, clicked / chosen). - Группы для ранжирования = одна сессия пользователя.
- Train/val split — по времени, не случайный, чтобы избежать утечки.
6. Онлайн-эксперимент.
- A/B тест: новая модель vs контроль. Метрика —
time_to_completeиmanual_overrides. - Power-анализ заранее: при MDE 1% времени — какой объём трафика нужен.
Реализация (бейзлайн на LightGBM)
import lightgbm as lgb
train = lgb.Dataset(X_train, y_train, group=group_train) # group: размер каждой сессии
val = lgb.Dataset(X_val, y_val, group=group_val, reference=train)
model = lgb.train(
params={
"objective": "lambdarank",
"metric": "ndcg",
"ndcg_eval_at": [1, 5, 10],
"learning_rate": 0.05,
},
train_set=train,
valid_sets=[val],
num_boost_round=500,
callbacks=[lgb.early_stopping(20)],
)Подводные камни
- Position bias. Пользователь чаще кликает на верхние позиции просто потому, что они сверху. Без коррекции (Inverse Propensity Scoring или counterfactual learning) модель учится на «позиции», а не на релевантности.
- Cold start пользователей без истории — нужны контентные эмбеддинги категорий + значение «средний пользователь».
- Утечка по времени. Если в train попадают будущие действия пользователя — оффлайн-NDCG будет великолепным, а в проде модель развалится.
- Online ≠ offline. Высокий NDCG не гарантирует роста бизнес-метрик. Всегда проверяйте через A/B.
Эталонный ответ
Listwise LTR (LambdaMART) поверх признаков «пользователь × кандидат × контекст», обучаемая на сессиях пользователей с группировкой. Метрики offline — NDCG/MRR, online — A/B по бизнес-таймингу. Обязательно учитывать position bias и временной split для валидации.