Глава 1 — Анатомия метрик

Retention: возвращались ли

18 мин
Чему научишься
  • понимать, что такое и как календарные даты превращаются в относительные дни D0, D1 и D7
  • считать , используя размер исходной когорты в знаменателе
  • задавать критерий «вернулся» — от него зависит значение метрики
  • различать retention «ровно на N-й день» и rolling retention
  • понимать, что такое незрелые когорты: пустая ячейка — это не ноль

Пять котов и один календарь

Retention отвечает на вопрос, который не могут задать ни DAU, ни : вернулись ли те же самые люди.

Чтобы на него ответить, нужна — группа пользователей с общим условием старта. В этом уроке таким условием будут первый визит и его дата: например, «все, кто впервые пришёл 1 марта». Пользователь попадает в такую когорту один раз и остаётся в ней до конца наблюдений.

Вот пять котов из чёрного ящика, даты их первых визитов и всех последующих заходов:

котпервый визитзаходил ещё
Барсик1 марта2 марта, 8 марта
Снежок1 марта
Пух2 марта3 марта, 9 марта
Муся5 марта6 марта
Рыжик5 марта12 марта

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

Курсант и робот-кот наблюдают голограмму, где группы капсул проходят одинаковые временные пути и часть капсул возвращается на контрольных точках.
Retention считают от размера когорты, а календарные даты для этого переводят в дни жизни: D0, D1, D7.

Календарь → относительные дни

D0 — день первого визита. Не «нулевой день месяца», а «нулевой день ЭТОГО пользователя». У Барсика D0 приходится на 1 марта, у Муси — на 5 марта. Дальше для каждого отсчитываем дни от его собственного D0.

В таблице отмечены только даты, когда кот заходил. Тире означает, что в этот день захода не было.

кот1 марта2 марта3 марта5 марта6 марта8 марта9 марта12 марта
БарсикD0D1D7
СнежокD0
ПухD0D1D7
МусяD0D1
РыжикD0D7

Один и тот же D1 приходится у разных котов на разные календарные даты: у Барсика это 2 марта, у Муси — 6 марта. И наоборот: 8 марта для Барсика — D7, а для Муси — D3, хотя в этот день она не заходила. Именно этот перевод и есть главный трюк : мы выравниваем всех по их собственному старту и после этого можем сравнивать поведение людей, пришедших в разные дни.

Зачем это нужно вместо простого сравнения «сколько пользователей было вчера и сколько сегодня»? Потому что общий DAU смешивает старых и новых пользователей. Продукт может за неделю потерять всех новых пользователей и при этом расти по DAU — если реклама приводит новых быстрее, чем уходят старые. Когортный анализ отделяет конкретную группу от общего потока и позволяет спросить: эти коты — вернулись ли они?

КалендарьAрег. 1 мартаBрег. 5 мартаCрег. 5 марта12345678мартВозраст когортыA1 мар2 мар8 марB5 мар6 мар12 марC5 мар6 мар12 марD0D1D7retention считается в возрасте когорты, а не в календаре
Каждый пользователь выравнивается по своему D0: календарные даты превращаются в возраст, и D1 Барсика встаёт рядом с D1 Муси.

Знаменатель — исходная когорта

Теперь посчитаем для наших пяти котов.

Когорта 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 марта:

определение «вернулся»вернулись на D1D1
любое событие в журнале45245.2%
открыл приложение (app_open)38038.0%
сделал заказ (purchase)616.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.

Когорта 1 марта на калькуляторе. Обрати внимание: во всех трёх формулах знаменатель один и тот же — 1000. Последняя строка считает уже другую метрику — дожитие от D1 к D7. Выше мы разобрали, что по итоговым числам его посчитать нельзя: неизвестно, сколько котов были активны и на D1, и на D7. Поэтому здесь мы принимаем это допущение явно — считаем, что все 190 активных на D7 были активны и на D1.
python · pandas
Практика: напиши код
Когорта 3 марта: 800 новых котов. Активны именно 4 марта (D1) — 296, именно 10 марта (D7) — 120. Посчитай d1 и d7 в процентах. Следи за знаменателем: он одинаковый для обеих отметок.
python · pandas
Практика: напиши код
Та же когорта 3 марта (800 котов, 296 на D1, 120 на D7; как и на калькуляторе, принимаем допущение, что все 120 активных на D7 были активны и на D1). Посчитай две вещи, которые легко перепутать с retention: survival_d1_to_d7 — какая доля вернувшихся на D1 дожила до D7, и churned_by_d7 — сколько котов из ИСХОДНОЙ когорты не были активны на D7.
python · pandas
Проверь себя
Когорта 1 марта — 1000 человек. На D1 вернулись 380, на D7 активны 190. Чему равен D7 retention?
Проверь себя
Сегодня 14 марта. В таблице D30 для когорты 10 марта пусто. Коллега предлагает поставить туда 0, «чтобы посчиталось среднее». Что не так?
Главное из урока
  • — группа пользователей с одинаковым днём первого визита; каждый пользователь попадает в неё один раз и остаётся в ней навсегда
  • D0 — день первого визита конкретного пользователя; календарные даты переводятся в возраст, поэтому разные пользователи выравниваются по своему старту
  • в знаменателе всегда стоит размер исходной когорты; 190 / 380 без данных о пересечении активных D1 и D7 — это просто отношение двух , а не D7 retention
  • «вернулся» нужно определить заранее: любое событие, открытие приложения или заказ дадут разные результаты
  • exact-day DN («ровно на N-й день») и rolling DN («на N-й день или позже») — разные метрики; напрямую сравнивать их как одну и ту же метрику нельзя
  • незрелые когорты оставляют пустыми: NaN ≠ 0

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