**Контекст:** Fintech-приложение анализирует воронку заявки на кредитную карту с учётом времени прохождения каждого шага.
**Данные:** DataFrame `app_events` — колонки: `user_id`, `event_type` (app_open, card_view, apply_start, docs_upload, approved, first_use), `created_at`, `session_id`.
**Задание:**
1. Постройте воронку конверсии для заявки на кредитную карту
2. Для каждого перехода рассчитайте: медианное время конверсии, p25/p75
3. Рассчитайте процент пользователей, уложившихся в SLA (24 часа)
4. Определите самое «узкое» место воронки
Структура для ориентира — реальные значения из эталонного решения.
import pandas as pd
import numpy as np
np.random.seed(42)
n_users = 8000
steps = ['app_open', 'card_view', 'apply_start', 'docs_upload', 'approved', 'first_use']
step_conv = [1.0, 0.50, 0.65, 0.55, 0.70, 0.80] # step-to-step конверсия
step_hours = [0, 0.5, 2, 8, 48, 24] # медианное время до шага (часы)
records = []
for uid in range(n_users):
base = pd.Timestamp('2024-01-01') + pd.Timedelta(hours=np.random.randint(0, 2160))
active = True
for i, (step, conv, hrs) in enumerate(zip(steps, step_conv, step_hours)):
if i > 0:
if np.random.random() > conv:
active = False
break
delay = max(0.01, np.random.exponential(hrs))
base += pd.Timedelta(hours=delay)
records.append({'user_id': uid, 'event_type': step, 'created_at': base})
events = pd.DataFrame(records)
# Pivot: одна строка — один пользователь, колонки — время каждого шага
step_times = {}
for step in steps:
s = events[events['event_type'] == step][['user_id', 'created_at']]
step_times[step] = s.rename(columns={'created_at': f't_{step}'})
# Строим сводную таблицу пользовательских путей
user_journey = step_times[steps[0]]
for step in steps[1:]:
user_journey = user_journey.merge(step_times[step], on='user_id', how='left')
# Анализ каждого перехода
SLA_HOURS = 24
results = []
for i in range(1, len(steps)):
prev, curr = steps[i - 1], steps[i]
prev_col, curr_col = f't_{prev}', f't_{curr}'
mask = user_journey[curr_col].notna() & user_journey[prev_col].notna()
subset = user_journey[mask].copy()
time_diff = (subset[curr_col] - subset[prev_col]).dt.total_seconds() / 3600
arrived_prev = user_journey[prev_col].notna().sum()
arrived_curr = user_journey[curr_col].notna().sum()
results.append({
'transition': f'{prev} → {curr}',
'users_from': arrived_prev,
'users_to': arrived_curr,
'step_cvr_pct': round(arrived_curr / arrived_prev * 100, 1),
'median_hours': round(time_diff.median(), 2),
'p25_hours': round(time_diff.quantile(0.25), 2),
'p75_hours': round(time_diff.quantile(0.75), 2),
'sla_compliance_pct': round((time_diff <= SLA_HOURS).mean() * 100, 1),
})
funnel_df = pd.DataFrame(results)
print("Воронка кредитной карты:")
print(funnel_df.to_string(index=False))
bottleneck = funnel_df.loc[funnel_df['step_cvr_pct'].idxmin()]
print(f"\nУзкое место: {bottleneck['transition']}")
print(f" Конверсия: {bottleneck['step_cvr_pct']}%")
print(f" Медианное время: {bottleneck['median_hours']} часов")
print(f" SLA compliance ({SLA_HOURS}h): {bottleneck['sla_compliance_pct']}%")
pandas воронка конверсия time-to-convert percentile
Это задание для уровня Middle. Для middle-аналитиков с опытом 1-3 года, требует уверенного владения темой и понимания edge cases.
Подобные задания в категории «Python» регулярно дают на собеседованиях аналитика данных в Яндекс, Сбер, Ozon, Авито, Тинькофф, Wildberries, T-Bank, X5, ВТБ и других крупных IT-компаниях. Тематика: pandas, воронка, конверсия, time-to-convert, percentile.
На реальном собеседовании на подобную задачу отводится 15-30 минут — оцениваются подход, корректность, обработка edge cases. Для тренировки рекомендуем сначала решить самостоятельно, потом сверить с эталонным решением и подсказками.
На zasqlpython.ru есть 482 Python задачи с проверкой через Pyodide, конспекты Python и pandas, AI мок-собеседование с разбором ваших ответов.
← Все задания