Задачи на воронки конверсии на собеседовании

Что спрашивают про воронки

Воронка (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 — что делать?

Это кейс, не расчёт:

  1. Уточнить нормальность: индустриальные бенчмарки — это 70% много или нет?
  2. Сегментировать: у всех 70% или у конкретной платформы/канала/гео?
  3. Проверить технику: не сломан ли шаг (баг, медленная загрузка)?
  4. Продуктовая гипотеза: что не так на этом шаге? UX, цена, недостающие опции оплаты?
  5. Эксперименты: A/B-тесты на улучшение шага.

Как тренироваться

Воронки — это паттерн «pivot + conditional aggregate» или «LEAD/LAG для sequence». Как только освоены, задачи решаются за 5 минут.

Тренажёр Карьерник содержит задачи на воронки: базовые, sequential, временные окна, сегментация. С разборами и сравнением SQL vs pandas решений.

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

Читайте также

FAQ

Считать воронку по пользователям или по событиям?

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

Нужно ли учитывать порядок?

Зависит от задачи. «Сколько купило из тех, кто посмотрел» — не обязательно порядок. «Эффективность воронки в правильной последовательности» — да, нужен порядок через LAG.

Что делать с пропущенными шагами?

Если пользователь может пропустить шаг (например, купить сразу без add_to_cart) — считайте его «не прошёл через промежуточный шаг». Или выкиньте шаг из воронки, если он необязательный.

Временное окно — зачем?

Без окна человек, зарегистрировавшийся в 2020 и купивший в 2026 — «прошёл воронку». На практике нужно понимание «конверсия за сессию / за 24 часа / за 30 дней». Временное окно привязывает метрику к реальному поведению.