Задачи на retention на собеседовании аналитика
Зачем на собесе считают retention
Retention — главная продуктовая метрика. Если кандидат путается в «D7 vs unbounded» или не умеет написать его в SQL — для продуктовой команды это red flag. Ниже разберём 10 типовых задач с собесов.
Терминология
Перед задачами — важные определения:
- Cohort — группа пользователей, объединённая датой регистрации (неделей/месяцем).
- Classic retention (D-retention) — пользователь считается удержанным, если активен именно в день D.
- Rolling retention — пользователь активен в день D или позже.
- Unbounded retention — активен хотя бы один раз после дня регистрации.
- DAU-based vs event-based — считаем по запуску приложения или по целевому событию.
На собесе всегда уточняйте — какой именно retention нужен.
Задача 1. Base retention D7
Дана таблица events (user_id, event_time). Посчитать retention D7 для когорты 2026-04-01.
SQL решение
WITH cohort AS (
SELECT DISTINCT user_id
FROM events
WHERE event_time::DATE = '2026-04-01'
),
returned AS (
SELECT DISTINCT user_id
FROM events
WHERE event_time::DATE = '2026-04-08'
)
SELECT
(SELECT COUNT(*) FROM cohort) AS cohort_size,
(SELECT COUNT(*) FROM cohort INTERSECT SELECT user_id FROM returned) AS retained,
ROUND(100.0 *
(SELECT COUNT(*) FROM cohort INTERSECT SELECT user_id FROM returned)
/ NULLIF((SELECT COUNT(*) FROM cohort), 0), 2) AS retention_pct;Pandas решение
cohort = events[events['date'] == '2026-04-01']['user_id'].unique()
returned = events[events['date'] == '2026-04-08']['user_id'].unique()
retention = len(set(cohort) & set(returned)) / len(cohort)Задача 2. Retention D1, D7, D30 для всех когорт
WITH user_first AS (
SELECT user_id, MIN(event_time::DATE) AS cohort_date
FROM events GROUP BY user_id
),
activity AS (
SELECT uf.user_id, uf.cohort_date,
(e.event_time::DATE - uf.cohort_date) AS day_num
FROM user_first uf
JOIN events e USING (user_id)
)
SELECT
cohort_date,
COUNT(DISTINCT user_id) AS cohort_size,
COUNT(DISTINCT user_id) FILTER (WHERE day_num = 1) * 1.0 / COUNT(DISTINCT user_id) AS d1,
COUNT(DISTINCT user_id) FILTER (WHERE day_num = 7) * 1.0 / COUNT(DISTINCT user_id) AS d7,
COUNT(DISTINCT user_id) FILTER (WHERE day_num = 30) * 1.0 / COUNT(DISTINCT user_id) AS d30
FROM activity
GROUP BY cohort_date
ORDER BY cohort_date;Классическая когортная таблица, спрашивают часто.
Задача 3. Когортный retention — pivot
Построить когортную таблицу: строки — неделя регистрации, столбцы — недели с регистрации, значения — % удержанных.
Pandas решение
df['cohort'] = df.groupby('user_id')['date'].transform('min').dt.to_period('W')
df['active_period'] = df['date'].dt.to_period('W')
df['weeks_since'] = (df['active_period'] - df['cohort']).apply(lambda x: x.n)
cohort_sizes = df.groupby(['cohort', 'weeks_since'])['user_id'].nunique().unstack()
retention = cohort_sizes.divide(cohort_sizes[0], axis=0)
# Визуализация
import seaborn as sns
sns.heatmap(retention, annot=True, fmt='.0%', cmap='YlGnBu')Попробовать силы на подобных вопросах проще всего в тренажёре Карьерник — прямо в Telegram, без регистрации через сайт.
Задача 4. Rolling retention D7
Считается активным на D7, если был активен в дни 7-13 (а не строго в D7).
WITH cohort AS (
SELECT user_id FROM events WHERE event_time::DATE = '2026-04-01'
),
active_window AS (
SELECT DISTINCT user_id FROM events
WHERE event_time::DATE BETWEEN '2026-04-08' AND '2026-04-14'
)
SELECT COUNT(DISTINCT c.user_id) * 1.0 / (SELECT COUNT(*) FROM cohort) AS d7_rolling
FROM cohort c
JOIN active_window a USING (user_id);Rolling retention плавнее classic — меньше флуктуаций от выходных.
Задача 5. Unbounded retention
Пользователь считается удержанным, если зашёл хотя бы раз после когортного дня.
WITH cohort AS (
SELECT user_id, MIN(event_time::DATE) AS first_day
FROM events GROUP BY user_id
HAVING MIN(event_time::DATE) = '2026-04-01'
)
SELECT COUNT(*) AS total,
COUNT(*) FILTER (
WHERE EXISTS (
SELECT 1 FROM events e
WHERE e.user_id = c.user_id AND e.event_time::DATE > c.first_day
)
) * 1.0 / COUNT(*) AS unbounded_retention
FROM cohort c;Задача 6. Разница активных пользователей в D7 между Android и iOS
WITH cohort AS (
SELECT user_id, platform FROM users
WHERE registered_at::DATE = '2026-04-01'
),
returned AS (
SELECT DISTINCT user_id FROM events
WHERE event_time::DATE = '2026-04-08'
)
SELECT c.platform,
COUNT(*) AS cohort_size,
COUNT(*) FILTER (WHERE r.user_id IS NOT NULL) * 1.0 / COUNT(*) AS d7
FROM cohort c
LEFT JOIN returned r USING (user_id)
GROUP BY c.platform;Типичный вопрос при разборе A/B: «сравним retention по сегментам».
Задача 7. Почему D7 упал на 5 п.п. — как расследовать
Это не чисто расчётная задача — это кейс. Структура ответа:
- Проверить данные — трекер не сломан, ETL не упал.
- Декомпозировать по платформам, каналам, гео.
- Связать с релизами — что выкатили за неделю.
- Проверить маркетинг — не изменился ли mix каналов (Simpson's paradox).
Подробный разбор — кейс retention упал.
Задача 8. Retention по неделям для юзеров с разным первым событием
Одни пользователи при регистрации проходят онбординг, другие — нет. Сравнить retention.
WITH cohort AS (
SELECT user_id,
CASE WHEN completed_onboarding THEN 'onb' ELSE 'no_onb' END AS variant
FROM users WHERE registered_at::DATE = '2026-04-01'
),
active_d7 AS (
SELECT DISTINCT user_id FROM events
WHERE event_time::DATE = '2026-04-08'
)
SELECT c.variant,
COUNT(*) AS cohort_size,
COUNT(*) FILTER (WHERE a.user_id IS NOT NULL) * 1.0 / COUNT(*) AS d7_retention
FROM cohort c
LEFT JOIN active_d7 a USING (user_id)
GROUP BY c.variant;Пройти 30–50 задач по теме за вечер можно в Telegram-тренажёре. Это то, что отличает «знаю» от «уверенно отвечу на собесе».
Задача 9. Visualize retention curve
retention_curve = df.groupby('days_since_signup')['user_id'].nunique() / \
df[df['days_since_signup'] == 0]['user_id'].nunique()
import matplotlib.pyplot as plt
plt.plot(retention_curve)
plt.xlabel('Days since signup')
plt.ylabel('Retention')
plt.show()На собесе могут попросить на бумажке нарисовать ожидаемую форму кривой — экспоненциальный спад.
Задача 10. Retention и Churn — связь
Retention + Churn = 1 (для одного периода)Если D7 retention = 40%, значит D7 churn = 60%. Это не LTV, не CAC, не ARPU — это две стороны одной монеты за период.
Важно: обычно в продуктовых задачах retention считают с хорошей стороны (% вернулись), churn — с плохой (% ушли). Но метрика одна и та же.
Подробнее — retention vs churn.
Как тренироваться
Retention — тема, которая проверяет не SQL, а продуктовое мышление. Если вы умеете считать когорты — вы middle. Если вы умеете интерпретировать их и предлагать действия — senior.
Тренажёр Карьерник содержит блок на retention: D1/D7/D30, когорты, unbounded, rolling, разбор кейсов.
Совет: на собесе, услышав «посчитайте retention», первым вопросом спросите «D-retention, rolling или unbounded?» Это сразу ставит +1 балл за понимание.
Читайте также
- Как считать retention
- Когортный анализ
- Retention в SQL
- Retention vs churn
- Кейс: retention упал на собеседовании
FAQ
D7 = «вернулся через неделю» или «вернулся в седьмой день»?
Зависит от определения. Classic D7 — строго в день 7. Rolling D7 — в интервале дней 7-13. Bracket D7 — неделя после регистрации. На собесе всегда уточняйте.
Retention по неделям или по дням?
Для молодых продуктов — по дням (D1-D30). Для зрелых — по неделям и месяцам (W1-W12, M1-M6). Кривая retention длинного продукта — это месяцы, не дни.
Как визуализировать retention лучше всего?
Тепловая карта когортной таблицы — когорты по строкам, период по столбцам, % retention в ячейках. Это сразу показывает динамику и позволяет заметить улучшения в новых когортах.
Что важнее — retention или churn?
Одно и то же, просто с разных сторон. Retention для роста продукта, churn для удержания и отчётности. На собесах предпочитают retention, потому что легче обсуждать «как улучшить», чем «как снизить».