Когортный анализ: полный гайд

Что такое когортный анализ

Когортный анализ — метод, при котором пользователей делят на группы (когорты) по общему признаку и отслеживают поведение каждой группы во времени. Без когорт вы видите средние по больнице. С когортами — видите, что именно улучшается или ухудшается, и когда это началось.

На собеседованиях аналитиков когортный анализ спрашивают в двух форматах: «объясните принцип» и «напишите SQL-запрос, который строит когортную таблицу». Если вы готовитесь к интервью по продуктовой аналитике, эту тему нужно знать от и до.

Зачем нужны когорты

Представьте: в марте retention D7 вырос с 10% до 15%. Продукт стал лучше? Необязательно. Возможно, просто изменился источник трафика, и пришли более мотивированные пользователи. А может, вы запустили push-уведомления, и это работает.

Когортный анализ позволяет:

  • Отделить эффект продукта от эффекта привлечения. Если новые когорты удерживаются лучше при тех же каналах — продукт реально улучшился.
  • Найти точку деградации. Если когорта марта резко хуже когорты февраля — ищите, что изменилось между этими периодами.
  • Оценить LTV. Когорты показывают, как накапливается выручка с группы пользователей по мере их «жизни» в продукте.
  • Измерить влияние изменений. Запустили новый онбординг — сравните когорту «до» и «после» по retention, конверсии, среднему чеку.

Типы когорт

Когорты по времени привлечения (acquisition cohorts)

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

Пример: когорта «1-7 марта» — все, кто зарегистрировался на этой неделе. Смотрим, какая доля из них вернулась через 7 дней, 14 дней, 30 дней.

Это то, что обычно имеют в виду, когда говорят «когортный анализ» без уточнения.

Поведенческие когорты (behavioral cohorts)

Пользователей группируют по действию, а не по дате. Например:

  • Когорта «прошли онбординг» vs «не прошли»
  • Когорта «сделали 3+ заказа в первую неделю» vs «сделали 1 заказ»
  • Когорта «пришли из Instagram» vs «пришли из поиска»

Поведенческие когорты отвечают на вопрос «какие действия коррелируют с долгосрочным удержанием». На собеседованиях это часто формулируется как «найдите aha-moment» или «определите magic number».

Как строить когортную таблицу: пошагово

Разберём построение таблицы retention по когортам — это самая типичная задача.

Шаг 1. Определите когорту. Для каждого пользователя найдите дату первого действия (регистрация, первый визит, первая покупка). Это будет дата когорты.

Шаг 2. Определите периоды. Решите, с какой гранулярностью считать: дни (D1, D7, D30), недели (W1, W2, W4) или месяцы (M1, M2, M3). Для мобильных приложений обычно дни, для SaaS — месяцы.

Шаг 3. Для каждой пары (когорта, период) посчитайте число активных пользователей. Активность — это то, что вы определили как целевое действие (любой визит, покупка, прохождение урока и т.д.).

Шаг 4. Разделите на размер когорты. Получите процент — это и есть retention для данной когорты на данный период.

Шаг 5. Обрежьте незавершённые когорты. Если когорта существует 10 дней, D30 для неё ещё не определён. Не показывайте его в таблице.

Результат — таблица, где строки = когорты, столбцы = периоды, ячейки = проценты:

Когорта Размер D0 D1 D7 D14 D30
1-7 фев 320 100% 24% 11% 7% 4%
8-14 фев 285 100% 27% 13% 9% 5%
15-21 фев 310 100% 31% 16% 11% 7%
22-28 фев 340 100% 30% 15% 10% --

Видно: каждая следующая когорта удерживается лучше. Что-то в продукте работает.

SQL: когортная таблица retention

Полный запрос на PostgreSQL. Считает retention по недельным когортам для произвольного набора дней.

WITH cohort AS (
    -- Шаг 1: определяем когорту каждого пользователя
    SELECT
        user_id,
        MIN(event_date) AS first_date,
        DATE_TRUNC('week', MIN(event_date))::DATE AS cohort_week
    FROM user_activity
    GROUP BY user_id
),
activity AS (
    -- Шаг 2: все уникальные пары (пользователь, дата)
    SELECT DISTINCT
        user_id,
        event_date
    FROM user_activity
),
retention AS (
    -- Шаг 3: для каждого пользователя считаем day_number
    SELECT
        c.cohort_week,
        c.user_id,
        a.event_date - c.first_date AS day_number
    FROM cohort c
    INNER JOIN activity a ON c.user_id = a.user_id
)
SELECT
    cohort_week,
    COUNT(DISTINCT user_id) AS cohort_size,
    -- Шаг 4: retention по каждому дню
    ROUND(100.0 * COUNT(DISTINCT CASE WHEN day_number = 1
        THEN user_id END) / COUNT(DISTINCT user_id), 1) AS d1,
    ROUND(100.0 * COUNT(DISTINCT CASE WHEN day_number = 3
        THEN user_id END) / COUNT(DISTINCT user_id), 1) AS d3,
    ROUND(100.0 * COUNT(DISTINCT CASE WHEN day_number = 7
        THEN user_id END) / COUNT(DISTINCT user_id), 1) AS d7,
    ROUND(100.0 * COUNT(DISTINCT CASE WHEN day_number = 14
        THEN user_id END) / COUNT(DISTINCT user_id), 1) AS d14,
    ROUND(100.0 * COUNT(DISTINCT CASE WHEN day_number = 30
        THEN user_id END) / COUNT(DISTINCT user_id), 1) AS d30
FROM retention
-- Шаг 5: фильтруем незавершённые когорты
WHERE cohort_week <= CURRENT_DATE - INTERVAL '30 days'
GROUP BY cohort_week
ORDER BY cohort_week;

Логика: находим дату первого визита каждого пользователя, привязываем его к недельной когорте, затем для каждого последующего визита вычисляем day_number — сколько дней прошло. Агрегируем через COUNT(DISTINCT CASE WHEN ...), чтобы получить число вернувшихся на конкретный день.

Обратите внимание: фильтр WHERE cohort_week <= CURRENT_DATE - INTERVAL '30 days' обрезает когорты, которые ещё не «прожили» 30 дней. Без него D30 последних когорт будет 0%, и таблица введёт в заблуждение.

SQL: когорты по выручке

Когортный анализ применяется не только к retention. Второй по частоте кейс — накопленная выручка (cumulative revenue) по когортам.

WITH cohort AS (
    SELECT
        user_id,
        DATE_TRUNC('month', MIN(order_date))::DATE AS cohort_month
    FROM orders
    GROUP BY user_id
),
monthly_revenue AS (
    SELECT
        o.user_id,
        c.cohort_month,
        -- Номер месяца жизни пользователя (0 = первый месяц)
        EXTRACT(YEAR FROM AGE(DATE_TRUNC('month', o.order_date), c.cohort_month)) * 12
            + EXTRACT(MONTH FROM AGE(DATE_TRUNC('month', o.order_date), c.cohort_month))
            AS month_number,
        SUM(o.revenue) AS revenue
    FROM orders o
    INNER JOIN cohort c ON o.user_id = c.user_id
    GROUP BY o.user_id, c.cohort_month,
        DATE_TRUNC('month', o.order_date)
)
SELECT
    cohort_month,
    COUNT(DISTINCT user_id) AS cohort_size,
    ROUND(SUM(CASE WHEN month_number = 0 THEN revenue END)
        / COUNT(DISTINCT user_id), 2) AS arpu_m0,
    ROUND(SUM(CASE WHEN month_number <= 1 THEN revenue END)
        / COUNT(DISTINCT user_id), 2) AS cum_arpu_m1,
    ROUND(SUM(CASE WHEN month_number <= 2 THEN revenue END)
        / COUNT(DISTINCT user_id), 2) AS cum_arpu_m2,
    ROUND(SUM(CASE WHEN month_number <= 5 THEN revenue END)
        / COUNT(DISTINCT user_id), 2) AS cum_arpu_m5
FROM monthly_revenue
GROUP BY cohort_month
ORDER BY cohort_month;

Здесь для каждой месячной когорты считаем cumulative ARPU — среднюю выручку на пользователя нарастающим итогом. Столбец cum_arpu_m5 показывает, сколько в среднем принёс пользователь когорты за первые 6 месяцев жизни.

Такая таблица напрямую используется для оценки LTV и payback period.

Как читать когортную таблицу

По диагонали — календарное время

Каждая диагональ когортной таблицы соответствует одной и той же календарной дате. Если на диагонали все значения упали — произошло что-то глобальное (сбой сервера, праздники, релиз с багом). Если провал только в одной строке — проблема именно с этой когортой.

По строкам — жизненный цикл когорты

Читая строку слева направо, вы видите, как «стареет» когорта. Типичная кривая: резкое падение в первые дни, затем плато. Если плато не формируется и кривая продолжает снижаться — продукт не создаёт привычку.

По столбцам — тренд по когортам

Сравните D7 для разных когорт сверху вниз. Если значения растут — продукт улучшается. Если падают — деградация. Если скачут хаотично — возможно, когорты слишком маленькие или сильно меняется состав трафика.

На что обращать внимание

Улучшающиеся когорты. D7 растёт от когорты к когорте — значит, изменения в продукте работают. Сопоставьте с датами релизов, чтобы понять, что именно дало эффект.

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

Сезонность. Январские когорты могут быть лучше, потому что в каникулы люди активнее пробуют новое. Не путайте сезонный всплеск с реальным улучшением продукта. Сравнивайте год к году.

Стабилизация кривой. Если к D30 retention выходит на плато (например, 5% и дальше не падает) — у продукта есть ядро. Если кривая стремится к нулю — пользователи рано или поздно уходят все.

Аномальная когорта. Одна когорта резко отличается от соседних. Проверьте: не было ли в этот период промо-акции, вирального поста, технических проблем. Одна аномалия — не тренд.

Визуализация: heatmap

Лучший способ визуализировать когортную таблицу — heatmap (тепловая карта). Строки — когорты, столбцы — периоды, цвет ячейки — значение метрики.

Основные правила:

  • Используйте градиентную палитру от тёмного (высокое значение) к светлому (низкое). Зелёный для retention, синий для revenue — привычные для читателя конвенции.
  • Не забудьте обрезать незавершённые когорты — пустые ячейки в правом нижнем углу таблицы нормальны и ожидаемы.
  • Подписывайте размер когорты — heatmap без размеров вводит в заблуждение. Когорта из 10 человек с retention 50% — это 5 пользователей, а не успех продукта.
  • Добавьте столбец с абсолютными числами рядом с процентами — это помогает не обманываться маленькими выборками.

В Python heatmap строится через seaborn.heatmap(), в Google Sheets — через условное форматирование. В BI-инструментах (Tableau, Metabase, Redash) есть встроенные шаблоны когортных таблиц.

Вопросы с собеседований

"Что такое когортный анализ и зачем он нужен?"

Когортный анализ — метод, при котором пользователей группируют по общему признаку (обычно дате регистрации) и отслеживают метрики каждой группы во времени. Нужен, чтобы отделить эффект изменений продукта от изменений в составе аудитории. Без когорт вы не можете ответить на вопрос «продукт стал лучше или просто пришли другие пользователи».

"Напишите SQL для когортной таблицы retention."

Решение приведено выше. Ключевые моменты, которые оценивает интервьюер: правильное определение когорты через MIN(event_date), вычисление day_number через разность дат, фильтрация незавершённых когорт.

"D1 retention упал для последней когорты. Как будете разбираться?"

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

"Чем отличаются acquisition и behavioral когорты?"

Acquisition когорты группируют по дате привлечения — все, кто пришёл в одну неделю. Behavioral когорты — по действию: «сделали покупку на первой неделе», «использовали фичу X». Acquisition когорты показывают тренд по времени, behavioral — помогают найти действия, которые предсказывают удержание.

"Как определить, что продукт улучшается, глядя на когортную таблицу?"

Сравнить один и тот же столбец (например, D7) для разных когорт. Если значения растут от когорты к когорте при стабильном источнике трафика — продукт улучшается. Важно контролировать состав когорт: если параллельно с улучшением D7 изменился канал привлечения, рост может быть вызван изменением аудитории, а не продукта.

"Как строить когорты для подписочного продукта?"

Для SaaS обычно используют месячные когорты по дате подписки и считают churn rate (обратная retention) по месяцам: M1, M2, M3. Ключевая особенность — нужно учитывать план подписки (месячная vs годовая) и считать когорты отдельно для каждого плана. Смешивание месячных и годовых подписчиков в одну когорту даст бессмысленные числа.

Больше вопросов по SQL и продуктовой аналитике — в соответствующих разделах.


Потренируйтесь решать задачи по когортному анализу и продуктовым метрикам в Карьернике — тренажёре для подготовки к собеседованиям аналитиков.

FAQ

Что такое когортный анализ простыми словами?

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

Как написать SQL-запрос для когортного анализа?

Ключевые шаги: найти дату первого действия каждого пользователя через MIN(event_date), вычислить day_number как разность между датой активности и датой когорты, затем агрегировать через COUNT(DISTINCT CASE WHEN ...) для каждого дня retention. Не забудьте отфильтровать незавершённые когорты.

Чем отличаются acquisition когорты от behavioral когорт?

Acquisition когорты группируют пользователей по дате привлечения — все, кто пришёл в одну неделю. Behavioral когорты группируют по действию: «сделали покупку на первой неделе» или «использовали фичу X». Первые показывают тренд по времени, вторые помогают найти действия, предсказывающие удержание.

Как понять, что продукт улучшается, глядя на когортную таблицу?

Сравните один и тот же столбец (например, D7 retention) для разных когорт сверху вниз. Если значения растут от когорты к когорте при стабильном источнике трафика — продукт действительно улучшается. Важно контролировать состав когорт, чтобы рост не был вызван изменением аудитории.