Python и pandas на собеседовании: 20 задач для аналитика
Практический разбор задач по Python и pandas на собеседовании аналитика: фильтрация, groupby, merge, даты, пропуски, отладка и объяснение результата.
На Python-собеседовании аналитика обычно не ждут олимпиадный алгоритм. Проверяют, можешь ли ты взять таблицу, понять её зерно, аккуратно преобразовать данные и объяснить, почему результат заслуживает доверия. Задачи на pandas часто выглядят коротко, но в них спрятаны дубли, пропуски, типы дат и неправильный знаменатель.
Коротко
Решай задачу через маленькие проверяемые шаги: осмотр таблицы, нормализация типов, фильтр, агрегация, проверка. Не превращай одну строку pandas в демонстрацию магии. Читаемый код и ясное объяснение обычно сильнее редкого метода, который ты не можешь защитить.
- До расчёта проверь shape, dtypes, пропуски и уникальность ключа.
- После merge проверь количество строк и ожидаемую кардинальность.
- Для пользователей используй `nunique`, для событий — сначала опиши зерно.
- Даты приводи к одному типу и сравнивай полуинтервалами.
- Объясняй не только что делает код, но и какой бизнес-вопрос он закрывает.
Как читать условие на Python
Перед кодом назови объект результата. Если просят “выручку по пользователям”, одна строка должна быть на user_id. Если просят “активность по дням”, результат будет на day, а пользователь может встречаться в исходном наборе много раз. Эта фраза помогает выбрать `groupby`, `nunique` и порядок соединений.
Затем уточни, что делать с пропусками и дублями. Пропущенный channel — это unknown или ошибка источника? Две строки с одним order_id — повтор или позиции одного заказа? Без этих вопросов можно идеально написать код, который считает не то.
| Вопрос | Пример ответа |
|---|---|
| Что означает строка? | одна позиция заказа или один заказ |
| Какой ключ результата? | user_id и календарный месяц |
| Что считать событием? | только оплаченный заказ |
| Как обрабатывать NULL? | unknown для канала, ошибка для суммы |
| Как проверить результат? | сверить число заказов и сумму с источником |
Задачи 1–4: фильтры, условия и новые колонки
Базовые задачи просят оставить оплаченные заказы, выбрать пользователей из сегмента или создать флаг “новый покупатель”. Важно помнить, что в pandas для нескольких условий нужны `&` и скобки, а сравнение дат должно выполняться после `to_datetime`. При создании колонки лучше использовать `np.select` или `Series.where`, если условия нужно читать как бизнес-правило.
На собеседовании покажи, что можешь сохранить исходный DataFrame и создать отдельный срез. `.copy()` после фильтра делает намерение явным и уменьшает риск неожиданного изменения исходных данных.
orders['created_at'] = pd.to_datetime(orders['created_at'])
is_paid = orders['status'].eq('paid')
is_full_month = orders['created_at'].between(
'2026-07-01', '2026-07-31 23:59:59', inclusive='both'
)
july_paid = orders.loc[is_paid & is_full_month].copy()
july_paid['is_large_order'] = july_paid['amount'].ge(5000)Задачи 5–7: groupby, agg и pivot
Частый промпт: посчитать выручку, число заказов и покупателей по каналу и месяцу. Сначала запиши зерно результата. Затем используй named aggregation, чтобы столбцы говорили сами за себя. `count` считает непустые значения в выбранной колонке, `size` — строки группы, `nunique` — уникальные сущности. Эти операции нельзя менять местами без понимания результата.
Pivot удобен для отчёта, но не всегда нужен для расчёта. Для проверки и дальнейших JOIN обычно проще оставить длинный формат: одна строка на месяц и канал. На интервью проговори, зачем тебе широкая таблица и как обработаешь отсутствующую комбинацию.
summary = (orders.loc[orders['status'].eq('paid')]
.groupby(['month', 'channel'])
.agg(revenue=('amount', 'sum'),
orders=('order_id', 'nunique'),
buyers=('user_id', 'nunique'))
.reset_index())
summary['arpu'] = summary['revenue'] / summary['buyers']Задачи 8–10: merge и контроль размножения
Дана таблица users и таблица orders. Нужно добавить канал регистрации и посчитать выручку по каналам. До merge выясни, уникален ли user_id в users. Если там несколько записей на пользователя, соединение размножит заказы. Для критичных расчётов используй `validate='many_to_one'`: pandas остановит код, если справочник нарушает ожидаемый контракт.
После соединения проверь число строк, долю unmatched и сумму денег до и после. Не исправляй проблему через `drop_duplicates()` без понимания, какую строку оставляешь. Дедупликация — это бизнес-правило, а не косметическая операция.
enriched = orders.merge(
users[['user_id', 'channel']],
on='user_id',
how='left',
validate='many_to_one',
indicator=True,
)
print(enriched['_merge'].value_counts())
print(enriched['amount'].sum(), orders['amount'].sum())Задачи 11–13: пропуски, дубли и типы
Интервьюер может показать таблицу, где amount содержит числа и строки, channel пустой у части пользователей, а order_id повторяется. Правильный ответ не начинается с `fillna(0)` для всех колонок. Сначала определи смысл. Нулевой discount может быть корректен, а неизвестный источник нельзя автоматически назвать органикой.
Для дублей покажи, как отличишь повтор загрузки от нескольких позиций заказа. Для типов используй `to_numeric(errors="coerce")`, но сразу посчитай, сколько значений не распарсилось. Молчаливое превращение ошибки в NaN не является очисткой.
- `isna().mean()` — доля пропусков по колонкам.
- `duplicated(subset=[...])` — проверка повторов по ожидаемому ключу.
- `pd.to_numeric` и `pd.to_datetime` — явное приведение типов.
- `value_counts(dropna=False)` — увидеть неизвестные категории.
- После очистки сохранить число удалённых или изменённых строк.
Задачи 14–16: даты и временные окна
Попросить месячную динамику или время до первой покупки — простой способ проверить, понимаешь ли ты даты. Не группируй строки по строковому `created_at` и не сравнивай timestamps из разных таймзон. Создай нормализованное поле, зафиксируй границу периода и проверь первые и последние значения.
Для retention можно получить cohort_day через `groupby('user_id')['created_at'].transform('min')`, но не называй результат retention, пока не определил return event и горизонт. Python делает вычисление, а смысл всё равно задаётся аналитиком.
events['occurred_at'] = pd.to_datetime(events['occurred_at'], utc=True)
events['cohort_day'] = events.groupby('user_id')['occurred_at'].transform('min').dt.date
events['active_day'] = events['occurred_at'].dt.date
events['day_n'] = (
events['active_day'] - events['cohort_day']
).map(lambda delta: delta.days)
d7 = events.loc[events['day_n'].eq(7), 'user_id'].nunique()Задачи 17–18: apply, vectorization и сложное правило
Если условие можно выразить операциями над колонками, сначала выбирай векторизацию. `apply` допустим, когда правило действительно построчное или требует нескольких полей и его нельзя ясно выразить маской. На собеседовании важно не повторять “apply всегда медленный”, а объяснить масштаб и читаемость решения.
Сложное правило лучше вынести в именованную функцию и покрыть маленькими примерами. Проверь обычную строку, пропуск, границу и неожиданный тип. Рабочий аналитик думает не только о том, как получить ответ сейчас, но и как коллега поймёт его через месяц.
Задачи 19–20: отладка и воспроизводимость
Покажи, как ищешь ошибку в расчёте: уменьшаешь данные до маленького примера, проверяешь промежуточные формы и сравниваешь с ручным ответом. Если график внезапно вырос вдвое, сначала проверь merge и дубли, а не меняй визуальный масштаб.
Для воспроизводимости зафиксируй вход, версию библиотек, дату среза и порядок запуска. Ноутбук, который работает только после ручного запуска ячеек в случайном порядке, не является надёжным решением. Даже на собеседовании полезно сказать, какой тест или контрольный DataFrame ты добавишь после расчёта.
«Я получил таблицу на уровне user_id и month. Теперь проверю уникальность ключа, сравню сумму с источником и отдельно посмотрю пользователей без channel. Если контроль проходит, результат можно отдавать в визуализацию».
Мини-кейс end-to-end: один DataFrame, три проверки
Возьми таблицу событий и реши задачу “найти пользователей, которые активировались за 24 часа, а затем посчитать их D7”. Сначала приведи occurred_at к UTC или бизнесовой таймзоне и зафиксируй signup_at. Затем найди первое meaningful action и вычисли активацию. После этого отдельным шагом проверь активность на седьмой день. Не объединяй всё в одну цепочку: промежуточные таблицы нужны для контроля.
Три проверки обязательны. Первая — один user_id имеет одну дату регистрации. Вторая — activation_at не раньше signup_at. Третья — D7 считается от всей когорты, а не только от активированных. Если ответ отличается от SQL-версии, сравни списки user_id на каждом шаге, а не только финальные проценты.
events['occurred_at'] = pd.to_datetime(events['occurred_at'], utc=True)
cohort = users[['user_id', 'signup_at']].drop_duplicates('user_id')
value = events[events['event_name'].eq('core_action')].merge(cohort, on='user_id')
value = value.loc[value['occurred_at'].ge(value['signup_at'])]
first_value = value.groupby('user_id')['occurred_at'].min()
activated = first_value.lt(cohort.set_index('user_id')['signup_at'] + pd.Timedelta('24h'))Какие ошибки в pandas замечают сразу
Красные флаги на собеседовании — `inplace=True` без объяснения, chained assignment, `count()` вместо `nunique()`, merge без `validate`, заполнение всех пропусков нулём и ручная работа со строковыми датами. Ни один из этих приёмов не запрещён навсегда, но кандидат должен понимать, когда они меняют результат или усложняют поддержку.
Не нужно произносить теорию на каждый метод. Достаточно коротко связать решение с риском: “Здесь использую `nunique`, потому что считаю пользователей, а не события”; “Добавляю `validate`, чтобы справочник не размножил строки”; “Сохраняю длинный формат, потому что дальше будет merge”.
Как тренировать pandas без заучивания методов
Возьми одну таблицу заказов и реши на ней десять разных вопросов: месячная выручка, первая покупка, повторная покупка, топ-категория, средний чек, пропуски канала, время до заказа, сегмент пользователей и сверка с SQL. Меняй зерно результата и каждый раз записывай контрольное число.
Полезно проговаривать метод в терминах результата: “groupby уменьшает таблицу до месяца и канала”, “merge добавляет атрибут пользователя”, “nunique считает людей, а не события”. Тогда навыки переносятся на новый датасет и не зависят от того, встретилось ли в условии слово `orders`.
Материалы по теме
Как тестировать аналитические расчёты на Python и pandas
Практический гайд по тестам для аналитика: проверить метрики на маленьком датасете, поймать регрессию и защитить расчёт от тихих изменений.
Читать материал
Как ускорить pandas: память, типы и обработка больших файлов
Что делать, если pandas медленно работает или не помещает файл в память: категории, downcast, chunksize, Parquet и контроль размера данных.
Читать материал
Pandas apply и векторизация: как писать быстрее и понятнее
Когда использовать apply, почему векторные операции быстрее и как переписать медленный построчный расчёт в pandas.
Читать материал