Собесов

khangich (Intuit): спроектировать ранжирование

ML / Data ScienceML System DesignСложнаяSenior

Условие

Спроектируйте систему ранжирования для продукта 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)],
)

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

  1. Position bias. Пользователь чаще кликает на верхние позиции просто потому, что они сверху. Без коррекции (Inverse Propensity Scoring или counterfactual learning) модель учится на «позиции», а не на релевантности.
  2. Cold start пользователей без истории — нужны контентные эмбеддинги категорий + значение «средний пользователь».
  3. Утечка по времени. Если в train попадают будущие действия пользователя — оффлайн-NDCG будет великолепным, а в проде модель развалится.
  4. Online ≠ offline. Высокий NDCG не гарантирует роста бизнес-метрик. Всегда проверяйте через A/B.

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

Listwise LTR (LambdaMART) поверх признаков «пользователь × кандидат × контекст», обучаемая на сессиях пользователей с группировкой. Метрики offline — NDCG/MRR, online — A/B по бизнес-таймингу. Обязательно учитывать position bias и временной split для валидации.

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

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

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