Перейти к содержанию

Eval-протокол (анти-утечка)

Главный научный риск проекта — утечки в оценке cold-start. Протокол ниже + тесты-инварианты сплиттера защищают от них.

Anti-leakage invariant

Test-cold айтемы должны отсутствовать в donor training, validation features для tuning, popularity computation и neighbor construction. Donor scores, которые используют transfer methods, считаются только по warm items.

flowchart LR
    A[All interactions] --> B[Pick pseudo-cold items]
    B --> C[Train: warm items only]
    B --> D[Val-cold: tune meta-methods]
    B --> E[Test-cold: final metrics]
    C --> F[Train donor]
    F --> G[Warm donor scores]
    G --> H[Transfer method]
    D --> H
    H --> E

Pseudo-cold split (как делаем)

  1. Сплит по айтемам, не по взаимодействиям. Случайно (стратифицированно) выбираем подмножество warm-айтемов, объявляем их псевдо-cold и полностью удаляем все их взаимодействия из:
  2. train донора,
  3. расчёта Grouped MP и популярностей,
  4. построения соседей (similarity).
  5. Стратификация псевдо-cold по категориям и бакетам популярности — иначе оценка смещается к голове/хвосту распределения.
  6. Контент-фичи cold считаются только из их статики (без таргет-лика из их же взаимодействий). TF-IDF / нормировки / popularity-приоры — только по train-корпусу.
  7. Тюнинг гиперпараметров (k в KNN, λ в Ridge, …) — на отдельном cold-валидационном фолде, не на тесте.
  8. Опционально — temporal split (айтемы, появившиеся после момента T): честнее random item-holdout, ближе к проду. Естественно ложится на KION (есть время).

Обучение супервизорных мета-методов (нюанс протокола)

Мета-методы (stacking, stacking_plus, logreg_calib) обучают мету на val-cold фолде (айтемы вне train донора и вне test). Их признаки (linmap-сигнал, аффинность, популярность) считаются leak-free, метки — из val-cold (не из test).

Текущая реализация runner обучает мету по тому же множеству пользователей, что и eval (test_users, выбранные как пользователи с взаимодействиями по test-cold айтемам). Это не утечка исхода теста (val-метки ≠ test-метки; test-cold фичи/метки мета не видит) — подтверждено независимым ревью (codex). В рекомендациях пользователи всегда общие между обучением и оценкой, так что это не завышает результат. Строго говоря, в fit попадает членство пользователя в eval-наборе; для максимально пуристичного протокола мету стоит обучать на независимом от test множестве пользователей — отмечено как направление доработки (потребует донор-скоров для дополнительного набора пользователей).

Инвариант сплиттера (проверяется тестами)

  • set(cold_items) ∩ set(train.item_id) == ∅ и то же для val.
  • Взаимодействия cold-айтемов присутствуют только в test.
  • Донор физически не видит cold-айтемы (отдельный тест «no cold item in any donor training input»).
  • Детерминизм при фиксированном seed.

Метрики

  • Ranking-метрики — основное для сравнения с Grouped MP: Recall@k, Precision@k, MAP@k, NDCG@k, MRR, для k ∈ {1, 5, 10}.
  • AUC + RelaImpr — дополнительно. RelaImpr = (AUC_model − 0.5) / (AUC_base − 0.5) − 1.
  • Калибровка ортогональна ранжированию И AUC: Platt/isotonic — монотонные преобразования, поэтому НЕ меняют ни ranking, ни AUC (обе rank-based). Улучшают только logloss/Brier. Не считаем калибровку «методом трансфера».
  • Репортим разброс по нескольким сидам (cold-оценка шумная) и по бакетам популярности cold-айтемов.
Почему calibration отделена от ranking

Монотонная calibration может сделать scores лучшими вероятностями, но сохраняет порядок scores. Ranking metrics и AUC зависят от порядка, поэтому calibration сама по себе не превращает слабый ranking method в сильный cold-start transfer method.

Соглашения метрик (фиксируем СВОИ, не полагаемся на чужие либы)

  • Tie-breaking в top-k — детерминированный и документированный.
  • Пользователи без релевантных айтемов в test — исключаются из усреднения (документируем).
  • k > числа кандидатов — корректная деградация (без падения).
  • Точечная сверка с эталоном (sklearn) на простых кейсах, но контракт — наш.