В отчёте сравнивают D7 retention когорт на дату 4 января. Определите, почему расчёт для свежей когорты нель...

В отчёте сравнивают D7-retention когорт на дату 4 января. Определите, почему расчёт для свежей когорты нельзя сопоставлять со старой.

WITH events(user_id, cohort_date, event_date) AS (
  VALUES
    (1, DATE '2025-01-01', DATE '2025-01-01'),
    (1, DATE '2025-01-01', DATE '2025-01-08'),
    (2, DATE '2025-01-03', DATE '2025-01-03'),
    (3, DATE '2025-01-03', DATE '2025-01-04')
), report AS (
  SELECT DATE '2025-01-04' AS report_date
)
SELECT cohort_date,
       event_date - cohort_date AS day_n,
       COUNT(DISTINCT user_id) AS active_users
FROM events, report
WHERE event_date <= report_date
GROUP BY cohort_date, event_date - cohort_date;
Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

Свежая когорта ещё не достигла седьмого дня жизни, поэтому её D7-retention не наблюдаем, а не равен нулю. Это проявление правого цензурирования: на момент анализа часть пользователей ещё не могла проявить событие, необходимое для расчёта метрики.

Сравнивать D7 следует только для когорт, которым уже исполнилось минимум семь дней, либо явно помечать незрелые значения как недоступные.

Исторический контекст

Обычная агрегированная метрика продукта смешивает пользователей разного возраста. Когортный анализ появился как способ отделить дату привлечения или первого действия пользователя от последующего поведения и увидеть жизненный цикл группы.

Но разбиение на когорты создаёт дополнительное условие: одинаковые показатели нужно сравнивать на одинаковом возрасте когорты. Иначе различие может отражать не продуктовый эффект, а разную длительность наблюдения.

Постановка проблемы

В примере когорта 1 января к 4 января уже имеет наблюдения до третьего дня, но ещё не может иметь настоящий D7. Когорта 3 января наблюдается только до первого дня, поэтому отсутствие события на седьмой день ничего не говорит о её будущем поведении.

Если считать отсутствующие будущие события неактивностью, свежие когорты получат искусственно заниженный retention. Если исключить пользователей без будущих данных из знаменателя, показатель, наоборот, может стать искусственно завышенным: в анализе останутся только пользователи с возможностью наблюдения.

Подробное решение

Для D7-retention нужны две величины: размер когорты и наличие целевого события в интервале или в точке, соответствующей седьмому дню. У каждого пользователя должно быть не менее семи дней наблюдения после даты включения в когорту.

Правило для фиксированного календарного отчёта можно записать так:

SELECT cohort_date, COUNT(DISTINCT user_id) AS cohort_size, COUNT(DISTINCT CASE WHEN event_date = cohort_date + INTERVAL '7 day' THEN user_id END) AS d7_users FROM user_events WHERE cohort_date <= DATE '2025-01-04' - INTERVAL '7 day' GROUP BY cohort_date;

Фильтр оставляет только созревшие когорты. В реальной системе также нужно заранее зафиксировать определение D7: событие ровно на седьмой календарный день, событие в окне с шестого по восьмой день или хотя бы одно событие в течение первых семи дней. Эти варианты отвечают на разные продуктовые вопросы и не должны смешиваться.

У подхода есть компромисс: исключение незрелых когорт повышает корректность сравнения, но задерживает получение свежего сигнала. Для оперативного мониторинга можно отдельно показывать незрелые когорты с пометкой, что значение предварительное, но нельзя использовать их как полноценный результат D7.

Дополнительно следует учитывать часовые пояса, задержки загрузки событий, пропуски трекинга и смену определения целевого события. Это уже не устраняется одним фильтром зрелости и может привести к систематической ошибке даже у старых когорт.

Ситуация из практики

Команда после релиза увидела резкое падение D7-retention у пользователей, привлечённых в последние четыре дня, и собиралась откатить изменение. При проверке выяснилось, что отчёт подставлял ноль для пользователей, у которых седьмой день ещё не наступил.

Рассматривались три варианта. Исключить свежие когорты давало корректное сравнение, но уменьшало оперативность. Показывать нули было просто, однако создавало ложный сигнал. Строить прогноз будущего retention позволяло быстрее оценивать релиз, но добавляло модельные допущения и риск ошибки.

Выбрали первый вариант для принятия решений по эксперименту: D7 считался только по созревшим когортам, а свежие данные отображались отдельным слоем как предварительные. В результате решение об откате принимали по сопоставимым когортам, а задержку измерения учитывали явно, а не маскировали нулевыми значениями.

Что кандидаты часто упускают

  1. Отличается ли правое цензурирование от пропущенных событий трекинга?

Да. При правом цензурировании пользователь ещё не мог быть наблюдён до нужного момента: это ограничение времени анализа. При пропуске трекинга нужное время уже прошло, но событие могло не попасть в данные. Первую проблему решают фильтром зрелости, вторую — контролем качества событий, восстановлением данных или явной оценкой неопределённости.

  1. Можно ли считать D7 по всем когортам, используя только пользователей, доживших до седьмого дня?

Такой подход меняет знаменатель и обычно создаёт смещение выживших. Дожитие до седьмого дня может зависеть от поведения пользователя, поэтому исключение остальных смешивает сам retention с условием выживания. Для стандартного D7 знаменателем обычно служит вся корректно сформированная когорта, а в анализ включают только когорты, для которых у всех участников есть необходимое окно наблюдения.

  1. Чем отличается D7-retention от retention за первые семь дней?

D7-retention обычно проверяет активность в конкретный седьмой день, тогда как retention за первые семь дней проверяет наличие активности хотя бы в заданном семидневном окне. Пользователь, активный на второй день и не вернувшийся на седьмой, может попасть во вторую метрику, но не попасть в первую. Поэтому перед сравнением когорт нужно зафиксировать точное окно, границы дат и правило подсчёта знаменателя.