Разбор: рекомендательная лента
Проектируем по девяти шагам из 11.2.1 ленту товаров маркетплейса: метрики от заказов до NDCG, данные из логов показов, двухэтапная архитектура (коллаборативная фильтрация, двухбашенная модель и ANN, бустинг для ранжирования), холодный старт, петли обратной связи и смещение позиции, A/B-тест, салфетка — и где сюда приходят трансформеры.
Зачем это нужно
Заголовок раздела «Зачем это нужно»Рекомендательные системы — одна из самых массовых ML-задач в индустрии: ленты соцсетей, витрины маркетплейсов, музыка, видео, реклама. Для проектирования она особенно поучительна по двум причинам. Во-первых, у неё нет «правильного ответа»: хороший товар для пользователя — тот, который он купит, а узнаем мы это только показав его. Во-вторых, система сама создаёт данные, на которых учится: что не показали, то не кликнули.
Почти все кирпичи у вас есть: ансамбли деревьев и градиентный бустингградиентный бустингEN gradient boosting (GBDT)Реализации — XGBoost, LightGBM, CatBoost. (уроки 2.3.1 и 2.4.3), эмбеддинги и контрастивное обучение, ANN-поиск и метрики поиска (урок 8.2.2), статистика A/B-тестов (урок 1.3.4). Соберём их по девяти шагам из 11.2.1. Формулировка интервьюера: «Маркетплейс. На главной странице — лента товаров. 2 млн активных пользователей в день, 10 млн товаров. Спроектируйте ленту».
Шаг 1. Задача и ограничения
Заголовок раздела «Шаг 1. Задача и ограничения»| Вопрос | Почему важен | Допущение |
|---|---|---|
| Что оптимизируем: клики, заказы, выручку, возвращаемость? | от этого зависит целевая переменная | заказы и удержание; клики — вспомогательный сигнал |
| Сколько запросов к ленте? | нагрузка и бюджет | 3 сессии в день, в каждой 3 страницы по 20 товаров |
| Каталог и его обновление | отбор кандидатов и холодный старт | 10 млн товаров, 200 000 новых в сутки |
| Задержка | сколько моделей успеем применить | страница — за 150 мс на стороне рекомендателя (p99) |
| Бизнес-правила | этап переранжирования | только товары в наличии, 18+ — по настройкам, не больше двух товаров продавца подряд |
| Доля новых пользователей | холодный старт | заметная: маркетплейс растёт |
Границы: поиск — отдельная система (урок 11.2.4), рекламные места разыгрываются своим аукционом, лента лишь оставляет для них слоты.
Шаг 2. Метрики
Заголовок раздела «Шаг 2. Метрики»| Уровень | Метрики |
|---|---|
| Бизнесбизнес-метрикаEN business metricТо, ради чего строят систему: выручка, конверсия, удержание, доля вопросов, решённых без оператора. ML-метрики (точность, recall@k) полезны, только если связаны с ней. | заказы и выручка на пользователя, удержание (вернулся ли через 7 дней) |
| Онлайн | CTRкликабельность (CTR)EN click-through rateДоля показов, после которых был клик: клики / показы. Быстрая онлайн-метрика рекомендаций, рекламы и поиска; оптимизировать только её опасно — растут «кликбейтные» позиции. ленты, добавления в корзину, конверсия в заказ из ленты, глубина просмотра |
| Офлайн | recall@k отбора кандидатов, NDCGNDCG (нормированный дисконтированный выигрыш)EN normalized discounted cumulative gainМетрика порядка выдачи со степенями релевантности: DCG@k = Σ rel_i / log2(i + 1), NDCG@k = DCG@k / DCG@k идеальной выдачи. От 0 до 1; ошибка наверху списка стоит дороже, чем внизу.@k ранжирования, AUC и logloss модели клика |
| Защитныезащитная метрикаEN guardrail metricМетрика, которая не должна ухудшиться при выкатке новой версии, даже если главная растёт: задержка, доля жалоб, утечки персональных данных, стоимость запроса. | задержка, разнообразие (категорий в первых 20), доля новых товаров в показах, доля показов у 1% самых популярных товаров, возвраты, жалобы |
Почему нельзя взять одну CTR: по закону Гудхартазакон ГудхартаEN Goodhart's law«Когда мера становится целью, она перестаёт быть хорошей мерой». лента, обученная только на кликах, наполняется яркими картинками и дешёвыми мелочами — кликают много, покупают мало. Поэтому итоговая оценка товара — взвешенная сумма предсказанных вероятностей клика, добавления в корзину и заказа. Веса — продуктовое решение, их подбирают A/B-тестами.
recall@k — тот же, что в RAG: какая доля товаров, которые пользователь потом купил, попала в top-k. Порядок внутри top-k он не видит. NDCG@k учитывает порядок и степень интереса. Пусть выигрыш 1 — клик, 2 — корзина, 3 — покупка, тогда
Логарифм в знаменателе — «скидка» за позицию: первое место делится на 1, второе на 1.58, пятое на 2.58. Две выдачи из пяти товаров для одного пользователя:
| Позиция | 1 | 2 | 3 | 4 | 5 | DCG@5 | NDCG@5 |
|---|---|---|---|---|---|---|---|
| Выдача A | клик (1) | — | покупка (3) | — | корзина (2) | 0.687 | |
| Выдача B | покупка (3) | клик (1) | — | корзина (2) | — | 0.943 | |
| Идеал | покупка (3) | корзина (2) | клик (1) | — | — | 1 |
recall@5 у обеих выдач одинаков — все три интересных товара на месте, но B поставила покупку первой, и NDCG это видит. Встречается и вариант с выигрышем : он сильнее награждает покупки. Выберите один и не меняйте его при сравнении версий.
Шаг 3. Данные
Заголовок раздела «Шаг 3. Данные»Главный источник — логи: показы (что, кому, когда и на какой позиции), клики, корзины, заказы. Плюс каталог (категория, цена, бренд, продавец, текст, фото) и профиль (регион, устройство). Это неявная обратная связьнеявная обратная связьEN implicit feedbackСигналы поведения — показы, клики, добавления в корзину, покупки, время просмотра — вместо явных оценок. Их много, но они шумные и смещены тем, что вообще показали.: её много — 18 млн запросов ленты по 20 товаров дают 360 млн показов в сутки, — но она шумная и смещённая.
Ловушки этого шага:
- Негативы — это показы без клика, а не все остальные товары. Товар, который пользователь не видел, ничего о нём не говорит.
- Позицию нужно логировать. Без неё смещение позиции (шаг 5) не исправить.
- Делить по времени: учимся до дня D, проверяем после. Случайное разбиение подсказывает модели будущее — та же утечкаутечка данныхEN data leakage, что в уроке 2.4.4.
- Задержка метки: заказ приходит через часы после клика. Метка «заказал» собирается в окне атрибуции, например 24 часа, и обучающая выборка за вчера готова только сегодня.
- Боты и накрутки — чистить до обучения (урок 11.1.1).
Шаг 4. Бейзлайн без ML
Заголовок раздела «Шаг 4. Бейзлайн без ML»Популярное за 7 дней по региону и любимым категориям пользователя плюс «вы недавно смотрели». Это сильный бейзлайн: в задании урока он даёт recall@10 = 0.375, а item-item фильтр — 0.50. Он же — запасной режим, когда модели или хранилище признаков недоступны, и стартовая лента для новых пользователей.
Шаг 5. Модель: многоэтапная система
Заголовок раздела «Шаг 5. Модель: многоэтапная система»Применить тяжёлую модель ко всем 10 млн товаров нельзя: даже при 5 мкс на товар это 50 секунд работы ядра на один запрос. Поэтому рекомендатель — каскадмногоэтапная рекомендательная системаEN multi-stage (cascade) recommenderКаскад «отбор кандидатов → ранжирование → переранжирование»: каждая следующая ступень точнее и дороже, но видит всё меньше объектов. В китайской индустрии этапы называют «отзыв» (recall), «грубое ранжирование», «точное ранжирование» и «переранжирование»., где каждая ступень точнее и дороже предыдущей, но видит всё меньше объектов. Это та же идея, что «ретривер → реранкер» в RAG.
flowchart LR
U["Запрос ленты:<br/>пользователь, контекст"] --> C1["Item-item CF<br/>по недавней истории"]
U --> C2["Двухбашенная модель<br/>+ ANN"]
U --> C3["Популярное<br/>в интересных категориях"]
U --> C4["Новые товары:<br/>исследование"]
C1 --> M["Слияние, дедупликация,<br/>фильтр наличия: ~500"]
C2 --> M
C3 --> M
C4 --> M
M --> RK["Ранжирование:<br/>бустинг, ~200 признаков → 100"]
RK --> RR["Переранжирование:<br/>правила, разнообразие,<br/>рекламные слоты → 20"]
RR --> SCR["Экран"]
SCR -.->|"показы, клики,<br/>заказы, позиции"| LOG[("Логи → обучение")]Отбор кандидатов
Заголовок раздела «Отбор кандидатов»Отбор кандидатовгенерация кандидатов (отбор)EN candidate generation (retrieval stage)Первая ступень рекомендателя или поиска: из миллионов объектов быстро и грубо выбрать сотни–тысячи кандидатов несколькими источниками (коллаборативная фильтрация, ANN по векторам, популярное). Меряют recall@k. меряют recall@500: нашлись ли среди 500 кандидатов товары, которые пользователь потом купил. Источников несколько, потому что каждый видит своё.
Коллаборативная фильтрацияколлаборативная фильтрацияEN collaborative filteringРекомендации только по матрице взаимодействий «пользователь × товар», без признаков товаров: «товары, которые берут вместе с вашими» (item-item) или «что любят похожие на вас» (user-user). item-item. Матрица : строки — пользователи, столбцы — товары, единица — было взаимодействие. Два товара похожи, если их берут одни и те же люди: косинус между столбцами . Оценка товара для пользователя — сумма сходств с товарами его истории: . Пример: товар A брали 4 человека, товар B — 2, и оба покупателя B брали и A. Тогда . Офлайн для каждого товара хранят 50 ближайших соседей, онлайн остаётся сложить их для товаров из недавней истории. Это задание урока.
Матричные разложенияматричное разложение (в рекомендациях)EN matrix factorizationПриближение матрицы взаимодействий произведением U·Vᵀ: у каждого пользователя и товара — вектор размерности d (32–256), оценка интереса — их скалярное произведение. Родственник низкорангового приближения и SVD.. : у каждого пользователя и товара вектор размерности, скажем, 64, интерес — скалярное произведение. Это низкоранговое приближениенизкоранговое приближениеEN low-rank approximationЗамена матрицы ближайшей матрицей ранга r. По теореме Эккарта — Янга лучшая получается, если оставить r старших слагаемых SVD. из ступени 1, только обученное на наблюдаемых взаимодействиях. Слабое место — у нового товара нет строки в .
Двухбашенная модельдвухбашенная модельEN two-tower modelДве нейросети: «башня» пользователя и «башня» товара выдают векторы, оценка — их скалярное произведение. Векторы товаров считаются заранее и ищутся через ANN — как биэнкодер в поиске для RAG.. Две нейросети: «башня» пользователя (история, регион, устройство) и «башня» товара (категория, цена, эмбеддинг названия и фото) выдают векторы, оценка — их скалярное произведение. Учится контрастивно: пара «пользователь — купленный товар» — позитив, остальные товары батча — негативы из батчанегативы из батчаEN in-batch negativesВ контрастивном обучении негативами для пары служат чужие примеры того же батча: батч из B пар даёт каждой паре B − 1 негатив бесплатно.. Это биэнкодербиэнкодерEN bi-encoderЗапрос и документ кодируются независимо, сходство — скалярное произведение векторов. Векторы документов считаются заранее, поэтому поиск быстрый. из поиска для RAG, только вместо вопроса — пользователь. Векторы товаров считаются заранее и лежат в ANNприближённый поиск ближайших соседей (ANN)EN approximate nearest neighbor search (ANN)Поиск похожих векторов без полного перебора (HNSW, IVF, PQ) ценой небольшой потери полноты.-индексе (HNSWHNSW (иерархический граф «малого мира»)EN Hierarchical Navigable Small World (HNSW)Один из самых распространённых ANN-индексов в векторных БД — многослойный граф, по которому поиск спускается от редких верхних слоёв к плотным нижним; предложен Ю. Мальковым и Д. Яшуниным (arXiv:1603.09320)., урок 8.2.2). Башня товара работает по контенту, поэтому новый товар получает вектор сразу.
Ранжирование
Заголовок раздела «Ранжирование»Ранжирование видит ~500 кандидатов и может позволить себе дорогие признаки:
- товар: CTR и конверсия за 7 дней, цена, рейтинг, возвраты;
- пользователь: доли кликов по категориям, средний чек;
- пары «пользователь × товар»: доля кликов пользователя в категории товара, цена относительно его обычной;
- источники: оценка item-item, скалярное произведение башен;
- контекст: время, устройство.
Первая модель — бустинг (LightGBM, урок 2.4.3) с целями «клик» и «заказ». У LightGBM есть и цель lambdarank, которая
оптимизирует NDCG напрямую. Почему бустинг, а не нейросеть: на разнородных табличных признаках он сильный, быстрый на
CPU, а SHAP объясняет его решения. Нейросетевые ранжировщики окупаются на очень больших данных — пример в «Китайском
угле».
Переранжирование — правила поверх ранжирования: наличие, не больше двух товаров продавца подряд, штраф за почти одинаковые товары рядом (ради разнообразия), рекламные слоты.
Холодный старт
Заголовок раздела «Холодный старт»Холодный стартхолодный старт (в рекомендациях)EN cold startНовый пользователь или товар без истории взаимодействий: коллаборативной фильтрации не на что опереться. Помогают признаки контента, популярное по сегменту, быстрые сессионные сигналы и слоты для исследования. — новые пользователи и товары без истории. Новому пользователю — популярное по региону и источнику перехода, вопрос об интересах при входе и быстрые сессионные сигналы: первые три клика сразу меняют кандидатов, без ночного переобучения. Новому товару — вектор из башни товара и слоты исследования: допустим, 2 из 20 мест ленты отдаются новым товарам. Это компромисс исследования и использованияисследование и использованиеEN exploration vs. exploitationКомпромисс между «пробовать новое, чтобы узнать больше» и «делать то, что сейчас кажется лучшим».: сегодня теряем немного кликов, зато узнаём, какие новинки хороши, и не отрезаем новых продавцов от покупателей.
Петли обратной связи и смещение позиции
Заголовок раздела «Петли обратной связи и смещение позиции»Петля обратной связипетля обратной связиEN feedback loopМодель учится на данных, которые сама же и создала своими решениями: в рекомендациях популярное показывают чаще, оно собирает больше кликов и становится ещё популярнее. Разрывают исследованием и случайными показами.: модель показала товар A — A собрал клики — модель решила, что A хорош, и показывает его ещё чаще. Товары, которые ни разу не показали, шанса не получают, и показы концентрируются на узкой группе. Поэтому концентрация показов — защитная метрика, а исследование — обязательная часть системы.
Смещение позициисмещение позиции в кликахEN position bias (in click logs)Верхние позиции выдачи кликают чаще независимо от релевантности: их просто чаще видят. Клики без поправки на позицию учат модель повторять старый порядок.: верхние места кликают чаще просто потому, что их чаще видят. Допустим, небольшой эксперимент со случайным порядком товаров показал, что первую позицию просматривают всегда, пятую — в половине случаев, десятую — в 30%. Тогда CTR 3% на десятой позиции соответствует 10% среди тех, кто товар увидел, — товар лучше, чем кажется. Что с этим делать:
- Позицию — признаком при обучении, а при применении подставлять одну и ту же (например, 1) для всех кандидатов.
- Взвешивание по обратной склонности (IPS)взвешивание по обратной склонности (IPS)EN inverse propensity scoringПоправка на смещение в логах: каждый клик весят как 1 / p, где p — вероятность, что объект вообще заметили (зависит от позиции). Клик на 10-й позиции, которую видят редко, весит больше клика на первой.: клик на позиции с вероятностью просмотра весит .
- Малая доля трафика (около 1%) со случайным порядком внутри первых 20 — для оценки вероятностей просмотра и честных офлайн-метрик.
Шаг 6. Офлайн-оценка
Заголовок раздела «Шаг 6. Офлайн-оценка»Отбор кандидатов — recall@500 на покупках следующего дня. Ранжирование — NDCG@20 и AUC на логах показов. Подвох: логи содержат только то, что показала старая система, поэтому офлайн-метрика смещена в её пользу. Новая модель, поднявшая неизвестные ранее товары, офлайн ничего не получит — для них нет меток. Отсюда правило: офлайн-оценка — фильтр (не стало ли хуже на известном), а решение принимает онлайн-эксперимент. Срез метрик — по сегментам: новые и старые пользователи, категории, регионы.
Шаг 7. Онлайн-эксперимент
Заголовок раздела «Шаг 7. Онлайн-эксперимент»A/B-тест делит пользователей: показы одного человека связаны между собой, и если делить показы, один пользователь увидит обе ленты. По той же причине доверительный интервал считают по пользователям — бутстрэпбутстрэп (выборка с возвращением)EN bootstrap samplingОснова бэггинга (bagging) и случайного леса., который пересэмплирует пользователей целиком (урок 1.3.4). Если считать каждый показ независимым, интервал выйдет обманчиво узким.
Главная метрика — заказы на пользователя, вспомогательные — CTR и корзины, защитные — задержка, разнообразие, возвраты. Сколько нужно пользователей, чтобы заметить рост доли заказавших за день с 4% на 2% относительных (до 4.08%)? По формуле из урока 1.3.4:
Маленькие относительные эффекты требуют огромных выборок — поэтому рекомендации и тестируют на крупных сервисах. При 2 млн активных в день группы по 25% наберут столько за несколько дней, но тест идёт две недели: недельный цикл покупок и эффект новизныэффект новизныEN novelty effectВ первые дни A/B-теста пользователи активнее реагируют на любое изменение просто потому, что оно новое; через неделю-две эффект может исчезнуть. Поэтому тесты ленты и поиска не останавливают в первый же день. — в первые дни люди кликают на любое новое. Для быстрого сравнения двух ранжировщиков есть и интерливинг: в одной выдаче перемешивают результаты A и B и смотрят, чьи товары кликают чаще — ему нужно гораздо меньше трафика, но он сравнивает только порядок, а не бизнес-метрики.
Шаг 8. Сервинг и оценки на салфетке
Заголовок раздела «Шаг 8. Сервинг и оценки на салфетке»Нагрузка. 2 млн пользователей × 3 сессии × 3 страницы = 18 млн запросов в сутки, в среднем 208 в секунду. Пик вечером, коэффициент 3: 625 запросов в секунду.
Бюджет задержки 150 мс: источники кандидатов параллельно — 20 мс, сбор признаков — 40 мс, ранжирование — 30 мс, переранжирование — 10 мс, остальное — сеть и запас.
Память. Векторы башни товара: байта = 2.56 ГБ в float32, граф HNSW — ещё около 1.3 ГБ (32 связи по 4 байта на товар на нижнем слое). Таблица соседей item-item: соседей 8 байт (номер и сходство) = 4 ГБ. Всё помещается в память одного сервера, а реплики нужны ради отказоустойчивости.
Ранжирование. предсказаний бустинга в секунду. Порядок величины — единицы микросекунд на строку для ансамбля из сотен деревьев; при 5 мкс это 1.6 секунды работы ядра в секунду, с запасом 0.7 — три ядра. Сама модель дешёвая, дорого другое: значений признаков на запрос нужно достать из хранилища признаков за 40 мс. Узкое место рекомендателя — доставка признаков, а не модель.
Обучение. 360 млн показов в сутки; бустинг учат на выборке, например 50 млн строк × 200 признаков: в float32 это 40 ГБ — помещается в 128 ГБ RAM (LightGBM к тому же хранит признаки компактными гистограммами). Двухбашенную модель учат на GPU, векторы новых товаров пересчитывают каждый час.
Почему не LLM на каждый запрос. Prefill 1 000 токенов истории пользователя у модели 8B — 0.34 с работы RTX 4080 (формула из 11.2.1). При 625 запросах в секунду нужно карт. Поэтому классическая лента работает на CPU, а LLM приходят офлайн или в виде небольших последовательных моделей (раздел ниже).
Шаг 9. Мониторинг и итерации
Заголовок раздела «Шаг 9. Мониторинг и итерации»- Онлайн-метрики по сегментам: новые и старые пользователи, категории, регионы. Средняя по всем часто растёт, пока новичкам становится хуже.
- Здоровье конвейера: доля кандидатов от каждого источника, задержка обновления признаков, доля пустых признаков, распределение оценок модели, PSIиндекс стабильности популяции (PSI)EN population stability indexМера сдвига распределения признака: сумма (aᵢ − eᵢ)·ln(aᵢ/eᵢ) по категориям или по бинам числового признака. Пороги — эмпирическое правило: меньше 0.1 — мало, больше 0.25 — заметный сдвиг. признаков между неделями (урок 11.1.4).
- Экосистема: концентрация показов, доля новых товаров и продавцов в показах, разнообразие.
- Переобучение: бустинг — каждый день через офлайн-гейт, тревога, если модель не обновлялась больше двух суток.
- Долгосрочный контроль: небольшая группа пользователей надолго остаётся на старой системе. Только так видно накопленный эффект многих мелких изменений.
Где сюда приходят трансформеры и LLM
Заголовок раздела «Где сюда приходят трансформеры и LLM»- Последовательные рекомендациипоследовательные рекомендацииEN sequential recommendationПредсказание следующего действия по упорядоченной истории пользователя; товары играют роль токенов, а модель — часто трансформер (SASRec, BERT4Rec).. История пользователя — последовательность товаров, а следующий товар предсказывают как следующий токен. SASRec (Kang, McAuley, ICDM 2018) — причинное self-attention, как в вашей GPT из модуля 4.6; BERT4Rec учится восстанавливать замаскированные товары, как BERT. В ранжировании тот же приём — трансформер по истории поведения (BST, Alibaba, 2019).
- Генеративные рекомендациигенеративные рекомендацииEN generative recommendationПодход, где рекомендатель генерирует идентификаторы следующих товаров как последовательность токенов, а не оценивает каждый кандидат отдельно. Активное направление исследований с 2023–2024 годов.. В работе HSTU (ICML 2024) рекомендации переформулированы как генеративное моделирование последовательностей действий пользователя; авторы сообщают о законах масштабирования, похожих на LLM. Другая линия — «семантические ID»: товар кодируется короткой последовательностью токенов, и модель генерирует его токен за токеном. Направление активно развивается, и выводы отдельных компаний стоит проверять по первоисточникам.
- LLM как помощник, а не ранжировщик. Офлайн: извлечь атрибуты из описаний, получить эмбеддинги текста для холодного старта, сгенерировать синтетическую разметку. Онлайн: объяснение «почему вам это» для нескольких позиций и диалоговый помощник покупателя — по сути RAG из урока 11.2.2 с инструментами поиска по каталогу.
Компромиссы
Заголовок раздела «Компромиссы»| Развилка | Выбор | Цена | Передумаю, если… |
|---|---|---|---|
| Бустинг или нейросеть для ранжирования | бустинг | потолок на последовательных паттернах | данных станет на порядок больше, а сессионные сигналы важнее |
| Сколько кандидатов ранжировать | 500 | часть кандидатов отсекается грубо | recall@500 мал, а запас по задержке есть |
| Оптимизировать CTR или заказы | взвешенная сумма клик + корзина + заказ | сложнее объяснить и настроить | бизнес сменит цель, например на удержание |
| Исследование новых товаров | 2 слота из 20 | чуть ниже CTR сегодня | новинок мало, и они быстро набирают показы сами |
| Свежесть | бустинг раз в сутки, векторы товаров раз в час | реакция на тренды с задержкой | заметная доля продаж — короткие тренды |
Конспект ответа на собеседовании за 45 минут
Заголовок раздела «Конспект ответа на собеседовании за 45 минут»| Шаг | Мин | Что сказать |
|---|---|---|
| 1. Задача | 5 | «Оптимизируем заказы и удержание. 2 млн DAU, 10 млн товаров, 200 тысяч новых в сутки, 150 мс на страницу. Поиск и реклама — вне задачи». |
| 2. Метрики | 5 | «Бизнес — заказы на пользователя и удержание; онлайн — CTR, корзины; офлайн — recall@500 кандидатов и NDCG@20; защитные — разнообразие, концентрация показов, задержка. Только CTR — Гудхарт». |
| 3. Данные | 5 | «Логи показов с позициями, клики, заказы. Негатив — показ без клика. Делю по времени, метка заказа — в окне атрибуции». |
| 4. Бейзлайн | 3 | «Популярное по региону и категориям плюс недавно просмотренное — планка и запасной режим». |
| 5. Модель | 9 | «Каскад: кандидаты из item-item, двух башен с ANN, популярного и новинок → бустинг на ~200 признаках → правила и разнообразие. Холодный старт — башня товара и слоты исследования. Смещение позиции — позиция признаком, IPS, 1% случайного трафика». |
| 6. Офлайн | 3 | «recall@500 и NDCG@20 по сегментам; логи смещены к старой системе, поэтому офлайн — фильтр». |
| 7. Онлайн | 4 | «A/B по пользователям, интервал бутстрэпом по пользователям, две недели из-за недельного цикла и эффекта новизны; около миллиона пользователей на группу для +2% относительных». |
| 8. Сервинг | 6 | «625 запросов в секунду, 4 ГБ векторов и 4 ГБ соседей в памяти, ранжирование — несколько ядер CPU, узкое место — признаки. LLM на каждый запрос — 300 карт, поэтому офлайн». |
| 9. Мониторинг | 3 | «Сегменты, источники кандидатов, свежесть признаков, PSI, концентрация показов, долгосрочная контрольная группа». |
Самое частое углубление на этой задаче — холодный старт и смещение позиции: держите наготове числовой пример с вероятностью просмотра.
Практика
Заголовок раздела «Практика»Посчитайте recall@k и NDCG@k, напишите популярный бейзлайн и item-item коллаборативный фильтр и сравните их на синтетических покупках: у каждого пользователя любимая группа товаров, а два последних товара отложены как «будущее».
# Метрики рекомендаций и простейший item-item коллаборативный фильтр.
# Матрица R: строки — пользователи, столбцы — товары, 1 — было взаимодействие (покупка, клик), 0 — не было.
import math
import numpy as np
def recall_at_k(recommended, relevant, k):
"""Доля релевантных объектов, попавших в первые k рекомендаций.
recommended — список в порядке выдачи, relevant — множество (или список) релевантных.
Если релевантных нет — вернуть 0.0.
recall_at_k(["a", "b", "c", "d"], {"b", "d", "x"}, 2) == 1/3
"""
# TODO: ваш код
...
def ndcg_at_k(recommended, gains, k):
"""NDCG@k со степенями релевантности.
gains — словарь {объект: выигрыш}, например 1 — клик, 2 — корзина, 3 — покупка; остальным — 0.
DCG@k = Σ по позициям i = 1..k: gain_i / log2(i + 1). Идеальный DCG@k — те же выигрыши,
отсортированные по убыванию. NDCG = DCG / идеальный DCG; если идеальный DCG равен 0 — вернуть 0.0.
Пример из урока: ndcg_at_k(["a", "b", "c", "d", "e"], {"a": 1, "c": 3, "e": 2}, 5) ≈ 0.6875
"""
# TODO: ваш код
...
def item_item_similarity(R):
"""Косинусное сходство между столбцами (товарами) матрицы R.
S[i, j] = (R[:, i] · R[:, j]) / (|R[:, i]| · |R[:, j]|). Диагональ — нули (товар не рекомендует сам себя).
У товара без взаимодействий (нулевой столбец) все сходства — 0, без nan и предупреждений.
Ответ — массив numpy формы (число товаров, число товаров).
"""
# TODO: ваш код
...
def recommend_popular(R, user, k):
"""Бейзлайн без ML: k самых популярных товаров (больше всего единиц в столбце), которых у user ещё нет.
При равной популярности — сначала товар с меньшим индексом. Ответ — список int.
"""
# TODO: ваш код
...
def recommend_item_item(R, user, k, S=None):
"""Item-item CF: оценка товара j = Σ по товарам i из истории user значений S[i, j], то есть R[user] @ S.
Если S не передана — посчитать item_item_similarity(R). Уже виденные товары не рекомендовать.
Вернуть k товаров с наибольшей оценкой; при равенстве — меньший индекс. Ответ — список int.
"""
# TODO: ваш код
...
# ---- Данные и оценка (дано, менять не нужно) ----------------------------------------------
def make_data(n_users=200, n_items=60, n_groups=4, per_user=8, seed=0):
"""Синтетические покупки: у каждого пользователя любимая группа товаров, популярность по Ципфу.
Возвращает матрицу R (пользователи × товары, 0/1) и test — {пользователь: множество отложенных товаров}.
"""
rng = np.random.default_rng(seed)
group_of_item = np.arange(n_items) % n_groups
popularity = 1.0 / np.arange(1, n_items + 1) ** 0.8
R = np.zeros((n_users, n_items))
test = {}
for u in range(n_users):
p = popularity * np.where(group_of_item == u % n_groups, 6.0, 1.0)
items = rng.choice(n_items, size=per_user + 2, replace=False, p=p / p.sum())
R[u, items[:per_user]] = 1.0 # история — для обучения
test[u] = set(int(i) for i in items[per_user:]) # два отложенных товара — «будущее»
return R, test
def evaluate(recommender, R, test, k=10):
"""Средние recall@k и NDCG@k по пользователям; у отложенных товаров выигрыш 1."""
recalls, ndcgs = [], []
for u, relevant in test.items():
recs = recommender(R, u, k)
recalls.append(recall_at_k(recs, relevant, k))
ndcgs.append(ndcg_at_k(recs, {i: 1 for i in relevant}, k))
return {"recall": float(np.mean(recalls)), "ndcg": float(np.mean(ndcgs))}
# Пример из урока: две выдачи из пяти товаров, выигрыш 1 — клик, 2 — корзина, 3 — покупка
print("NDCG@5 выдачи A:", ndcg_at_k(["a", "b", "c", "d", "e"], {"a": 1, "c": 3, "e": 2}, 5))
print("NDCG@5 выдачи B:", ndcg_at_k(["c", "a", "x", "e", "y"], {"a": 1, "c": 3, "e": 2}, 5))
R, test = make_data()
S = item_item_similarity(R)
if S is not None and recall_at_k([0], {0}, 1) is not None:
print("популярное:", evaluate(recommend_popular, R, test))
print("item-item: ", evaluate(lambda R_, u, k: recommend_item_item(R_, u, k, S), R, test))
Проверь себя
Заголовок раздела «Проверь себя»- Лента — многоэтапная система: несколько источников кандидатов (item-item, двухбашенная модель с ANN, популярное, новинки) → ранжирование бустингом на сотнях признаков → правила и разнообразие.
- Метрики выстраиваются от заказов и удержания через CTR к recall@k кандидатов и NDCG@k ранжирования; одна CTR ведёт к кликбейту.
- Холодный старт закрывают контентная башня и слоты исследования; петлю обратной связи и смещение позиции — логи позиций, IPS и малая доля случайного трафика.
- A/B — по пользователям с бутстрэпом по пользователям и не короче двух недель; салфетка показывает, что узкое место — признаки, а LLM на каждый запрос стоила бы сотни карт.
Дальше: «Разбор: модерация контента и поиск» — две задачи, где всё решают пороги и цена ошибок.