← к модулям

Implicit-feedback трек (D2a)

Разворот датасета: берём реальный поведенческий лог (Brightkite check-ins) вместо чистых оценок MovieLens и прогоняем на нём то же самое — event schema, temporal split, next-item лейблы, baseline retrieval. RecSys на оценках и на behavior-логах — разные уровни сложности.

⚠ Датасет качается и обрабатывается локально (~60 МБ SNAP); страница показывает готовый маленький артефакт (VPS сырые логи не трогает). Взят плотный «ядро»-срез (активные юзеры × популярные места). Данные positive-only, без impressions.

Если термины implicit / positive-only / negatives пока не разложены по полкам — теория внизу страницы читается и до лабы, разделы не зависят друг от друга.

загрузка реального лога…

Теория простым языком

До сих пор всё крутилось вокруг MovieLens — чистых явных оценок. Большинство продуктовых рекомендательных систем учится преимущественно на поведенческих логах (клики, просмотры, покупки, чек-ины), иногда дополняя их explicit-сигналом — оценками, лайками, опросами. Здесь мы берём настоящий implicit-лог и прогоняем на нём то же самое — и сразу видно, что это другой уровень сложности.

Explicit ≠ implicit feedback

Explicit feedbackпользователь явно выразил мнение: оценка 1–5, лайк/дизлайк. Чисто, но редко и смещено (оценивают меньшинство, чаще на краях шкалы). Это MovieLens.
Implicit feedbackкосвенные сигналы из поведения: клик, просмотр, покупка, чек-ин. Их много, но они шумные и однобокие — наблюдаем в основном позитивы.
Почему explicit ratings не хватило
БылоMovieLens давал чистые явные оценки.
ПроблемаВ реальных продуктах оценки редки, зато поведения — море.
ИдеяУчиться на implicit-событиях: клики, просмотры, покупки, чек-ины.
Стало лучшеБольше данных, ближе к продукту, появляются сессии и время.
Осталось слабымТолько позитивы: нет impressions → нет наблюдаемых негативов.
ДальшеFeature-rich ranking и bias-aware оценка — полный implicit-трек (D2b).

Главная боль implicit: только позитивы

В нашем логе есть только чек-ины — куда человек пришёл. Нет записи, куда он не пришёл и что ему показали. Значит нет наблюдаемых негативов и нет impressions — а мы уже знаем из модуля про логи, что no-impression ≠ negative.

Positive-only / one-classвидим только «сделал», не видим «видел, но не сделал». Для pointwise/pairwise-моделей (logreg, BPR, two-tower) ненаблюдаемые пары приходится сэмплировать или взвешивать как суррогатные негативы — аккуратно, чтобы не выучить экспозицию вместо вкуса. А вот popularity и co-visitation отдельных негативов не требуют вовсе: они считаются по одним позитивам, поэтому и стоят в этом модуле первыми.
Пример. В открытых датасетах impressions почти всегда отсутствуют — это привилегированный корпоративный сигнал. Поэтому синтетический лог из модуля B1 (с показами и позициями) — не блажь, а замена того, чего в открытых данных нет.

Что меняется на реальных данных

Сильные стороны

  • Сигнала заметно больше: 2.0 млн чек-инов против ~100 тыс. оценок в MovieLens-small — примерно в 20 раз.
  • Есть timestamps и порядок действий → сессии восстанавливаются эвристикой (у нас: пауза > 6 ч), отсюда next-item и session-based постановки.
  • Ближе к проду: временная динамика, cold-start, дрейф — всё настоящее.

Слабые стороны

  • Только позитивы: для pointwise/pairwise-моделей негативы надо сэмплировать, экспозиция смещает.
  • Шум и дубли: повторные визиты, боты, автоплей — сигнал грязный.
  • Данные большие и разреженные: наивные модели считаются дольше и хуже.
co-visitation vs popularity — почему глобальная популярность слаба в этой warm next-POI постановке

В этом протоколе и на этом срезе наивная co-visitation (простой item-CF) превосходит popularity в 6–11 раз в зависимости от K (0.32 против 0.03 на K=10; на K=50 разрыв сужается до 5.8×) — она ловит личные регулярные места, а глобальный топ для вопроса «куда человек пойдёт дальше» почти не несёт информации: люди возвращаются в свои кафе и на свои станции. Причём наш baseline — самый примитивный: ненаправленная со-встречаемость внутри полной истории юзера, без сессий, окна, гео и направления переходов. Session-window, направленные (placet→placet+1) и geo-aware варианты могут оказаться сильнее — но «правильной» co-visitation одной не существует, и каждый вариант надо проверять замером.

И слово «бесполезна» тут было бы перебором: popularity остаётся фолбэком для cold-юзера (в нашем же замере это единственная из двух моделей, которая выдаёт им осмысленный список) и вполне может работать на другой поверхности — «популярное рядом», «трендовое сегодня». Слаба она именно в этой постановке: warm-аудитория, next-POI, 89% повторных визитов.

Историческая оговорка: до чистки строки-заглушки (секция 2 выше) popularity показывала Recall@10 = 0.33 и выглядела крепким baseline — но декомпозиция с фиксированной когортой показала, что около 92% этой величины давало прямое попадание в одно фиктивное «место». Хороший повод не доверять сильному baseline, пока не посмотрел, из чего он состоит.

Сильный сигнал тут — гео и последовательность (близость, время суток, маршрут, недавняя история). Их используют не только как фичи ранкера, но и как retrieval-источники: nearby-popular, last-location, session-transition, sequential item-to-item, graph/random-walk, ANN по sequence/user-эмбеддингам. То есть и retrieval (сейчас), и feature-rich ranking (Фаза 8), и sequential-модели (Фаза 9).

⚠️ Что может пойти не так

  • Считать «не кликнул/не был» негативом — вносишь экспозиционное смещение (см. модуль про логи).
  • Повторные события: один и тот же визит/клик много раз раздувает вес — нужна дедупликация/сессии.
  • Random split на логе оптимистичен вдвойне — тут особенно важен temporal split (B2).
  • Метрики implicit нельзя сравнивать с explicit «в лоб» — другая задача, каталог и сигнал (у нас revisits ↑ поднимают Recall).
  • Revisits: для next-POI повторный визит — валидный target; наивно удалять seen (как в MovieLens) меняет задачу на novel-POI.
  • Холодный старт массовый: в проде постоянно новые юзеры/айтемы — нужен fallback.
  • Сравнивать Recall с чужой работой, не сверив контракт: кто в знаменателе, что считается таргетом, исключены ли cold-айтемы — каждый из этих пунктов двигает число сильнее, чем выбор модели.

🧠 Проверь себя: В офлайн-замере у части eval-пользователей целевое место ни разу не встречается в train. Что с ними делать?

🧠 Проверь себя: В логе нашлись события с ВАЛИДНЫМ location_id, но координатами ровно (0.0, 0.0). Что с ними делать?

🧠 Проверь себя: Почему на implicit-логе нельзя просто взять «непосещённые места» как отрицательные примеры?

Где это в дорожной карте

Это D2a — минимальный implicit-трек: доказали, что схема данных, temporal split и baseline retrieval переносятся с MovieLens на реальный лог. Дальше на этих же данных: feature-rich ranking (гео/время/последовательность), мониторинг и capstone — полноценный production-like пайплайн от событий до serving.