Retention: возвращались ли
Чему научишься
- понимать, что такое и как календарные даты превращаются в относительные дни D0, D1 и D7
- считать , используя размер исходной когорты в знаменателе
- задавать критерий «вернулся» — от него зависит значение метрики
- различать retention «ровно на N-й день» и rolling retention
- понимать, что такое незрелые когорты: пустая ячейка — это не ноль
Пять котов и один календарь
Retention отвечает на вопрос, который не могут задать ни DAU, ни : вернулись ли те же самые люди.
Чтобы на него ответить, нужна — группа пользователей с общим условием старта. В этом уроке таким условием будут первый визит и его дата: например, «все, кто впервые пришёл 1 марта». Пользователь попадает в такую когорту один раз и остаётся в ней до конца наблюдений.
Вот пять котов из чёрного ящика, даты их первых визитов и всех последующих заходов:
| кот | первый визит | заходил ещё |
|---|---|---|
| Барсик | 1 марта | 2 марта, 8 марта |
| Снежок | 1 марта | — |
| Пух | 2 марта | 3 марта, 9 марта |
| Муся | 5 марта | 6 марта |
| Рыжик | 5 марта | 12 марта |
По календарным датам поведение этих котов трудно сравнивать: каждый начал пользоваться продуктом в свой день. Смысл появляется, когда мы переходим от абсолютного календаря к возрасту пользователя в продукте.

Календарь → относительные дни
D0 — день первого визита. Не «нулевой день месяца», а «нулевой день ЭТОГО пользователя». У Барсика D0 приходится на 1 марта, у Муси — на 5 марта. Дальше для каждого отсчитываем дни от его собственного D0.
В таблице отмечены только даты, когда кот заходил. Тире означает, что в этот день захода не было.
| кот | 1 марта | 2 марта | 3 марта | 5 марта | 6 марта | 8 марта | 9 марта | 12 марта |
|---|---|---|---|---|---|---|---|---|
| Барсик | D0 | D1 | — | — | — | D7 | — | — |
| Снежок | D0 | — | — | — | — | — | — | — |
| Пух | — | D0 | D1 | — | — | — | D7 | — |
| Муся | — | — | — | D0 | D1 | — | — | — |
| Рыжик | — | — | — | D0 | — | — | — | D7 |
Один и тот же D1 приходится у разных котов на разные календарные даты: у Барсика это 2 марта, у Муси — 6 марта. И наоборот: 8 марта для Барсика — D7, а для Муси — D3, хотя в этот день она не заходила. Именно этот перевод и есть главный трюк : мы выравниваем всех по их собственному старту и после этого можем сравнивать поведение людей, пришедших в разные дни.
Зачем это нужно вместо простого сравнения «сколько пользователей было вчера и сколько сегодня»? Потому что общий DAU смешивает старых и новых пользователей. Продукт может за неделю потерять всех новых пользователей и при этом расти по DAU — если реклама приводит новых быстрее, чем уходят старые. Когортный анализ отделяет конкретную группу от общего потока и позволяет спросить: эти коты — вернулись ли они?
Знаменатель — исходная когорта
Теперь посчитаем для наших пяти котов.
Когорта 1 марта — Барсик и Снежок, размер 2. На D1 вернулся один Барсик → D1 retention = 1 / 2 = 50%. На D7 — снова только Барсик → D7 = 50%.
Когорта 5 марта — Муся и Рыжик, размер 2. На D1 вернулась Муся → 50%. На D7 вернулся Рыжик → 50%. Обрати внимание: это разные коты. Retention не требует, чтобы на всех отметках возвращался один и тот же человек: для каждой отметки считается своя доля от одной и той же .
На реальных объёмах это выглядит так:
Когорта 'пришли 1 марта': 1000 котов ← ЗНАМЕНАТЕЛЬ для всех отметок
активны 2 марта (D1): 380 → D1 = 380 / 1000 = 38%
активны 8 марта (D7): 190 → D7 = 190 / 1000 = 19%
активны 31 марта (D30): 90 → D30 = 90 / 1000 = 9%
Главное правило, из-за которого ломается половина самодельных расчётов:
В знаменателе всегда исходная когорта — те самые 1000 человек, а не сколько-то оставшихся.
Заманчиво разделить 190 активных на D7 на 380 активных на D1 — получится 50%. Но это число нельзя интерпретировать как «половина вернувшихся на D1 вернулась и на D7»: из приведённых итоговых чисел неизвестно, сколько именно котов были активны в оба дня. Чтобы посчитать такую долю, в числитель нужно поставить количество котов, активных и на D1, и на D7, а в знаменатель — 380 котов, активных на D1. Это другая метрика, и данных для её расчёта здесь нет. Обычный D7 retention по-прежнему равен 190 / 1000 = 19%.
И ещё одно следствие фиксированного знаменателя: retention на отдельных дневных отметках не обязан убывать монотонно. Человек мог не зайти на D1, но зайти на D7 — как Рыжик. Поэтому D7 иногда чуть выше D3, особенно если на седьмой день приходится выходной или рассылка. Воронка убывает всегда, такой retention — нет.
Два решения, которые надо принять до расчёта
Решение 1: что значит «вернулся»
Точно как с «активным» из урока про DAU, слово «вернулся» само по себе ничего не определяет. На одной и той же 1 марта:
| определение «вернулся» | вернулись на D1 | D1 |
|---|---|---|
| любое событие в журнале | 452 | 45.2% |
открыл приложение (app_open) | 380 | 38.0% |
сделал заказ (purchase) | 61 | 6.1% |
Разброс — более чем в семь раз, и все три варианта законны. Для игры уместно считать возвращением открытие приложения. Для маркетплейса можно выбрать заказ, если важно отслеживать покупки после первого визита, или открытие приложения, если исследуется регулярное использование продукта. Заказ сильнее связан с выручкой, но происходит реже. Важно одно: определение выбрано осознанно, записано и не меняется молча.
Решение 2: «ровно на N-й день» или «на N-й день и позже»
Это два разных вида retention, и они дают разные числа.
Exact-day (classic) retention. D7 = доля когорты, активная именно в седьмой день. Строгая и чувствительная метрика: если человек заходил на D6 и D8, но пропустил D7, — в D7 retention он не попадает. Такой retention удобно сравнивать между когортами, и он привычен в мобильной аналитике. В этом курсе под DN мы всегда понимаем именно этот вид.
Rolling (unbounded) retention. D7 = доля когорты, у которой была активность на седьмой день ИЛИ позже. Такое определение отвечает на вопрос «человек ещё жив?», а не «зашёл ли он в конкретный день». Его значение не ниже exact-day retention и обычно меняется более плавно. При этом rolling retention зависит от даты, на которую собраны данные: если человек вернётся позже, уже рассчитанное значение может вырасти.
когорта 1 марта, кот заходил 2 и 9 марта
exact-day D7 (8 марта): НЕ засчитан — в этот день его не было
rolling D7: засчитан — 9 марта позже седьмого дня
Ни один из видов не «правильнее». Правильно — знать, какой перед тобой, и не сравнивать один с другим. Если в двух отчётах D7 отличается вдвое, первым делом проверь не продукт, а вид retention.
Незрелые когорты: пустая клетка — это не ноль
Сегодня 14 марта. Смотрим на две .
Когорта 1 февраля. В 2184 году февраль длится 29 дней, поэтому её D30 приходится на 2 марта. Этот день уже прошёл, данные собраны, значение известно.
Когорта 10 марта. Её D1 (11 марта) известен. Её D7 придётся на 17 марта — этот день ещё не наступил. Её D30 — на 9 апреля.
D1 D7 D30
1 февраля 41% 22% 11%
10 марта 39% ? ? ← ещё не прожито
Вопросительный знак — это не ноль. Ноль означал бы «никто не вернулся», то есть катастрофу. Здесь же он означает «мы пока не знаем»: когорта незрелая, ей просто не хватило календарного времени.
В таблицах и коде такое «неизвестно» обычно обозначают специальным значением — в pandas это NaN (not a number, «не число»), и мы подробно займёмся им в главе про грязные данные. Пока достаточно запомнить главное:
NaN ≠ 0. Неизвестное значение нельзя подменять нулём: при расчёте его пропускают или обрабатывают отдельно, а на графике оставляют разрыв, а не рисуют провал до нуля.
Вот чем это опасно на практике. Если посчитать средний D7 по всем когортам и подставить нули за незрелые, среднее рухнет — и появится «падение », которого нет. Если перед построением линии D30 заменить пустоты нулями, линия пойдёт вниз к последним датам просто потому, что этим когортам ещё нечего показывать.
Правило дознавателя: при сравнении когорт бери только те, что прожили нужный возраст. Хочешь сравнить D30 — рассматривай когорты не моложе 30 дней, остальные оставляй пустыми. Чтобы получить ранний сигнал, не пытаясь предсказывать будущее, смотри на D1, D3 или D7, если эти отметки уже созрели у всех сравниваемых когорт. Они помогают заметить изменения раньше, но не заменяют D30.
d1 и d7 в процентах. Следи за знаменателем: он одинаковый для обеих отметок.survival_d1_to_d7 — какая доля вернувшихся на D1 дожила до D7, и churned_by_d7 — сколько котов из ИСХОДНОЙ когорты не были активны на D7.Главное из урока
- — группа пользователей с одинаковым днём первого визита; каждый пользователь попадает в неё один раз и остаётся в ней навсегда
- D0 — день первого визита конкретного пользователя; календарные даты переводятся в возраст, поэтому разные пользователи выравниваются по своему старту
- в знаменателе всегда стоит размер исходной когорты; 190 / 380 без данных о пересечении активных D1 и D7 — это просто отношение двух , а не D7 retention
- «вернулся» нужно определить заранее: любое событие, открытие приложения или заказ дадут разные результаты
- exact-day DN («ровно на N-й день») и rolling DN («на N-й день или позже») — разные метрики; напрямую сравнивать их как одну и ту же метрику нельзя
- незрелые когорты оставляют пустыми:
NaN≠ 0
Дальше — когортная таблица: как все эти строки складываются в одну решётку и что в ней читать первым.