Офлайн и онлайн оценка

Урок объясняет разницу между офлайн-оценкой на исторических данных и онлайн-экспериментами (A/B-тестами) и почему офлайн часто вводит в заблуждение.

Офлайн-оценка считает метрики на сохранённых логах прошлого, а онлайн-оценка (A/B-тест) измеряет реальное поведение пользователей на живой системе.

Два мира оценки

Офлайн-оценка дёшева и быстра: прячем часть истории, обучаем, считаем precision@k и NDCG. Она незаменима для отсева заведомо плохих моделей. Но у неё есть фундаментальный изъян, из-за которого офлайн-улучшение не всегда переносится в реальный прирост.

Почему офлайн обманчив

  • Смещение показов (presentation bias). В логах есть только то, что старая система показала. Если пользователь не кликнул по товару, мы не знаем, не понравился он или его просто не показали. Новая модель, рекомендующая то, чего старая никогда не показывала, в офлайне выглядит «неправой», хотя в жизни могла бы сработать отлично.
  • Нет учёта реакции. Офлайн не видит, как пользователь поведёт себя, увидев новую выдачу: рекомендации меняют поведение, а исторические логи это не отражают.
  • Метрика — прокси. NDCG приближает удовлетворённость, но бизнес волнуют удержание и выручка, которые офлайн напрямую не измеряет.
офлайн:  модель ---> метрика на ЗАМОРОЖЕННЫХ логах прошлого
                       (видит лишь то, что показала старая система)

онлайн:  модель ---> живые пользователи ---> их реальные клики/покупки
                       (A/B: группа A vs группа B)

A/B-тест: золотой стандарт

В онлайн-эксперименте пользователей случайно делят на группы: контрольная видит старую систему, тестовая — новую. Через время сравнивают целевые метрики (CTR, удержание, выручку) и проверяют статистическую значимость различий — здесь напрямую работают знания из учебника «Статистика».

# упрощённое сравнение двух групп A/B-теста по CTR
def ctr(clicks, shows):
    return clicks / shows if shows else 0.0

control = {"clicks": 1200, "shows": 20000}
test    = {"clicks": 1350, "shows": 20000}
c = ctr(**control); t = ctr(**test)
uplift = (t - c) / c
print(f"CTR контроль: {c:.3%}")
print(f"CTR тест:     {t:.3%}")
print(f"Прирост:      {uplift:+.1%}")

Вывод:

CTR контроль: 6.000%
CTR тест:     6.750%
Прирост:      +12.5%

Как работает под капотом

Здоровый процесс — это воронка: офлайн быстро отсеивает плохие идеи, затем лучшие кандидаты проверяют онлайн на небольшой доле трафика, и только победивший A/B катят на всех. Важно следить за значимостью (не делать выводов по шуму малой выборки) и за метриками-«предохранителями» (guardrails): прирост кликов не должен ронять удержание или разнообразие. Для борьбы с presentation bias собирают данные с элементом случайного показа (exploration), чтобы офлайн меньше врал.

Частые ошибки

  • Катить модель только по офлайну. Офлайн-прирост NDCG не гарантирует роста реальных метрик; нужен A/B.
  • Останавливать тест по первому всплеску. Малая выборка шумит; ждите статистической значимости.
  • Смотреть одну метрику. Рост кликов может скрывать падение удержания — следите за guardrails.

Итоги

  • Офлайн-оценка дёшева и хороша для отсева, но страдает от presentation bias.
  • Офлайн-улучшение метрики не гарантирует реального прироста.
  • A/B-тест измеряет настоящее поведение и служит золотым стандартом.
  • Здоровый процесс — воронка офлайн → онлайн с проверкой значимости и guardrails.
Проверьте себя
1. Почему офлайн-оценка рекомендаций часто обманчива?
AОна слишком дорогая
BЛоги содержат лишь то, что показала старая система (presentation bias), и не видят реакции на новую выдачу
CОна требует живых пользователей
DОфлайн-метрики невозможно посчитать
2. Что считается золотым стандартом онлайн-оценки рекомендаций?
AМаксимизация NDCG на логах
BA/B-тест: сравнение поведения случайно разделённых групп с проверкой значимости
CОпрос разработчиков
DРазмер модели