Задачи на воронки конверсии на собеседовании
Что спрашивают про воронки
Воронка (funnel) — базовая продуктовая метрика, после retention. На собесе проверяют:
- Умение посчитать конверсию шагов.
- Учёт порядка событий (sequential).
- Обработка ветвящихся воронок.
- Интерпретация drop-off.
Ниже 10 задач в формате «SQL + pandas + интерпретация».
Задача 1. Базовая воронка view → cart → purchase
WITH u AS (
SELECT user_id,
MAX(CASE WHEN event = 'view' THEN 1 ELSE 0 END) AS v,
MAX(CASE WHEN event = 'add_to_cart' THEN 1 ELSE 0 END) AS c,
MAX(CASE WHEN event = 'purchase' THEN 1 ELSE 0 END) AS p
FROM events
GROUP BY user_id
)
SELECT
SUM(v) AS step1,
SUM(c) AS step2,
SUM(p) AS step3,
SUM(c) * 100.0 / NULLIF(SUM(v), 0) AS v_to_c,
SUM(p) * 100.0 / NULLIF(SUM(c), 0) AS c_to_p
FROM u;Важно: мы считаем по уникальным пользователям, а не событиям. Иначе человек с 10 покупками зашумит.
Задача 2. Воронка с учётом порядка (sequential)
Кука с событием view, но не в последовательности с cart — не засчитывается.
WITH seq AS (
SELECT user_id, event, event_time,
LAG(event) OVER (PARTITION BY user_id ORDER BY event_time) AS prev_event
FROM events
)
SELECT
COUNT(DISTINCT user_id) FILTER (WHERE event = 'view') AS step1,
COUNT(DISTINCT user_id) FILTER (WHERE event = 'add_to_cart' AND prev_event = 'view') AS step2,
COUNT(DISTINCT user_id) FILTER (WHERE event = 'purchase' AND prev_event = 'add_to_cart') AS step3
FROM seq;Проверяем, что события идут в правильном порядке.
Задача 3. Воронка с временным окном
Между view и purchase должно пройти не больше 24 часов.
WITH events_with_prev AS (
SELECT user_id, event, event_time,
LAG(event) OVER (PARTITION BY user_id ORDER BY event_time) AS prev_event,
LAG(event_time) OVER (PARTITION BY user_id ORDER BY event_time) AS prev_time
FROM events
)
SELECT COUNT(DISTINCT user_id) AS completed
FROM events_with_prev
WHERE event = 'purchase'
AND prev_event = 'view'
AND event_time - prev_time < INTERVAL '24 hour';Для продуктовых команд это типовое — без временного окна метрика завышается.
Попробовать силы на подобных вопросах проще всего в тренажёре Карьерник — прямо в Telegram, без регистрации через сайт.
Задача 4. Drop-off analysis
На каком шаге теряется больше всего пользователей?
WITH funnel AS (
SELECT
SUM(CASE WHEN event = 'step1' THEN 1 END) AS s1_users,
SUM(CASE WHEN event = 'step2' THEN 1 END) AS s2_users,
SUM(CASE WHEN event = 'step3' THEN 1 END) AS s3_users
FROM (SELECT DISTINCT user_id, event FROM events) u
)
SELECT
s1_users - s2_users AS drop_s1_to_s2,
s2_users - s3_users AS drop_s2_to_s3
FROM funnel;Вывод: шаг с наибольшим drop-off — кандидат на оптимизацию.
Задача 5. Воронка по каналам привлечения
WITH user_events AS (
SELECT u.channel, e.user_id,
MAX(CASE WHEN e.event = 'view' THEN 1 ELSE 0 END) AS v,
MAX(CASE WHEN e.event = 'purchase' THEN 1 ELSE 0 END) AS p
FROM users u
JOIN events e USING (user_id)
GROUP BY u.channel, e.user_id
)
SELECT channel,
SUM(v) AS views,
SUM(p) AS purchases,
SUM(p) * 100.0 / NULLIF(SUM(v), 0) AS conversion
FROM user_events
GROUP BY channel
ORDER BY conversion DESC;Типичная задача: «какой канал конвертит лучше, где сливаем бюджет?»
Задача 6. Pandas-решение классической воронки
user_events = df.pivot_table(
index='user_id', columns='event', values='event_time',
aggfunc='min' # первое время события
)
step1 = user_events['view'].notna().sum()
step2 = user_events['add_to_cart'].notna().sum()
step3 = user_events['purchase'].notna().sum()
print(f"{step1=}, {step2=}, {step3=}")
print(f"V→C: {step2/step1:.1%}, C→P: {step3/step2:.1%}")Задача 7. Время до конверсии (time to conversion)
WITH events AS (
SELECT user_id,
MIN(CASE WHEN event = 'signup' THEN event_time END) AS t_signup,
MIN(CASE WHEN event = 'first_purchase' THEN event_time END) AS t_purchase
FROM events GROUP BY user_id
)
SELECT
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY t_purchase - t_signup) AS median,
AVG(t_purchase - t_signup) AS avg_time
FROM events
WHERE t_purchase IS NOT NULL;Задача 8. Conversion by day of week
SELECT
EXTRACT(DOW FROM event_time) AS dow,
COUNT(DISTINCT user_id) FILTER (WHERE event = 'view') AS views,
COUNT(DISTINCT user_id) FILTER (WHERE event = 'purchase') AS buys,
COUNT(DISTINCT user_id) FILTER (WHERE event = 'purchase') * 100.0 /
NULLIF(COUNT(DISTINCT user_id) FILTER (WHERE event = 'view'), 0) AS conv
FROM events
GROUP BY dow
ORDER BY dow;Пройти 30–50 задач по теме за вечер можно в Telegram-тренажёре. Это то, что отличает «знаю» от «уверенно отвечу на собесе».
Задача 9. Воронка с сегментацией по платформе и каналу
SELECT u.platform, u.channel,
COUNT(DISTINCT e.user_id) FILTER (WHERE e.event = 'view') AS views,
COUNT(DISTINCT e.user_id) FILTER (WHERE e.event = 'purchase') AS buys
FROM users u
JOIN events e USING (user_id)
GROUP BY CUBE (u.platform, u.channel);CUBE даёт все уровни агрегации: iOS+organic, iOS+..., +paid, и т.д.
Задача 10. Интерпретация: drop-off 70% на шаге N — что делать?
Это кейс, не расчёт:
- Уточнить нормальность: индустриальные бенчмарки — это 70% много или нет?
- Сегментировать: у всех 70% или у конкретной платформы/канала/гео?
- Проверить технику: не сломан ли шаг (баг, медленная загрузка)?
- Продуктовая гипотеза: что не так на этом шаге? UX, цена, недостающие опции оплаты?
- Эксперименты: A/B-тесты на улучшение шага.
Как тренироваться
Воронки — это паттерн «pivot + conditional aggregate» или «LEAD/LAG для sequence». Как только освоены, задачи решаются за 5 минут.
Тренажёр Карьерник содержит задачи на воронки: базовые, sequential, временные окна, сегментация. С разборами и сравнением SQL vs pandas решений.
Совет: всегда уточняйте у интервьюера «нужна ли последовательность событий?» По умолчанию воронку считают без порядка — а потом оказывается, что человек купил до того, как посмотрел.
Читайте также
FAQ
Считать воронку по пользователям или по событиям?
По уникальным пользователям почти всегда. По событиям — завышает, т.к. один пользователь может несколько раз делать шаг.
Нужно ли учитывать порядок?
Зависит от задачи. «Сколько купило из тех, кто посмотрел» — не обязательно порядок. «Эффективность воронки в правильной последовательности» — да, нужен порядок через LAG.
Что делать с пропущенными шагами?
Если пользователь может пропустить шаг (например, купить сразу без add_to_cart) — считайте его «не прошёл через промежуточный шаг». Или выкиньте шаг из воронки, если он необязательный.
Временное окно — зачем?
Без окна человек, зарегистрировавшийся в 2020 и купивший в 2026 — «прошёл воронку». На практике нужно понимание «конверсия за сессию / за 24 часа / за 30 дней». Временное окно привязывает метрику к реальному поведению.