Pandas шпаргалка для аналитика

Зачем аналитику pandas

Pandas — основная библиотека Python для работы с табличными данными. На собеседованиях аналитиков Python-блок почти всегда сводится к pandas: загрузить данные, отфильтровать, сгруппировать, объединить таблицы, посчитать метрику. Те же операции, что и в SQL, но в коде.

Эта шпаргалка — не учебник, а справочник. Каждый раздел: короткое объяснение и рабочий пример. Держите под рукой перед собеседованием.

На собеседованиях аналитиков pandas спрашивают реже, чем SQL, но в секции live-coding без него не обойтись. Особенно в продуктовых компаниях, где аналитик работает в Jupyter.

Загрузка данных

import pandas as pd

# CSV
df = pd.read_csv('orders.csv')

# Excel
df = pd.read_excel('report.xlsx', sheet_name='Sheet1')

# SQL-запрос
from sqlalchemy import create_engine
engine = create_engine('postgresql://user:pass@host/db')
df = pd.read_sql('SELECT * FROM orders WHERE created_at >= %s', engine, params=['2025-01-01'])

# Из словаря
df = pd.DataFrame({
    'user_id': [1, 2, 3],
    'revenue': [100, 250, 80]
})

Базовый осмотр после загрузки:

df.shape          # (строки, столбцы)
df.dtypes         # типы данных
df.head(10)       # первые 10 строк
df.describe()     # статистика по числовым столбцам
df.info()         # типы + пропуски
df.isnull().sum() # количество пропусков по столбцам

Фильтрация: loc, iloc, булевы маски

Булева фильтрация

Самый частый способ — условие в квадратных скобках.

# Заказы дороже 1000
big_orders = df[df['amount'] > 1000]

# Несколько условий: & (и), | (или), ~ (не)
active_big = df[(df['amount'] > 1000) & (df['status'] == 'completed')]

# Фильтр по списку значений
target_users = df[df['city'].isin(['Москва', 'Санкт-Петербург'])]

# Строковый фильтр
gmail = df[df['email'].str.contains('gmail', na=False)]

Скобки вокруг каждого условия обязательны — без них Python неправильно разберёт приоритет операторов.

loc и iloc

loc — фильтрация по меткам (имена строк и столбцов). iloc — по числовым индексам.

# loc: строки по условию, конкретные столбцы
df.loc[df['amount'] > 1000, ['user_id', 'amount']]

# iloc: первые 5 строк, столбцы 0 и 2
df.iloc[:5, [0, 2]]

На собеседовании спрашивают: «Чем отличается loc от iloc?» Ответ: loc работает с именами, iloc — с позициями. loc включает правую границу среза, iloc — нет.

groupby и агрегация

Аналог GROUP BY в SQL. Группируем строки и применяем агрегатную функцию.

# Средний чек по городам
df.groupby('city')['amount'].mean()

# Несколько агрегатов
df.groupby('city')['amount'].agg(['mean', 'median', 'count'])

# Разные агрегаты для разных столбцов
df.groupby('city').agg(
    avg_amount=('amount', 'mean'),
    total_orders=('order_id', 'count'),
    unique_users=('user_id', 'nunique')
)

Метод agg с именованными агрегатами — самый чистый способ. Результат сразу с понятными названиями столбцов.

Если нужно отфильтровать группы после агрегации (аналог HAVING в SQL):

city_stats = df.groupby('city')['amount'].sum()
city_stats[city_stats > 100000]

merge: объединение таблиц

Аналог JOIN в SQL. Если вы знаете SQL-джойны, pandas merge — тот же набор операций.

# INNER JOIN — только совпадающие строки
result = orders.merge(users, on='user_id', how='inner')

# LEFT JOIN — все строки из левой таблицы
result = orders.merge(users, on='user_id', how='left')

# OUTER JOIN — все строки из обеих таблиц
result = orders.merge(users, on='user_id', how='outer')

# Ключи с разными именами
result = orders.merge(
    users,
    left_on='customer_id',
    right_on='id',
    how='left'
)
pandas how SQL-аналог Что остаётся
inner INNER JOIN Только совпадения
left LEFT JOIN Все из левой + совпадения
right RIGHT JOIN Все из правой + совпадения
outer FULL OUTER JOIN Все из обеих

После merge проверяйте размер результата. Если строк стало больше, чем в левой таблице, — скорее всего, в правой таблице дубликаты по ключу. Это частая ловушка и на собеседованиях, и в реальной работе.

# Проверка: появились ли дубликаты после merge
print(f'До: {len(orders)}, После: {len(result)}')

pivot_table и melt

pivot_table

Сводная таблица — аналог Excel pivot и SQL с CASE WHEN внутри агрегата.

# Средний чек по городу и месяцу
pivot = df.pivot_table(
    values='amount',
    index='city',
    columns='month',
    aggfunc='mean',
    fill_value=0
)

Строки — города, столбцы — месяцы, значения — средний чек. fill_value=0 заполняет пустые ячейки нулями.

Можно передать несколько агрегатов:

pivot = df.pivot_table(
    values='amount',
    index='city',
    aggfunc=['mean', 'sum', 'count']
)

melt

Обратная операция — из «широкого» формата в «длинный». Нужна, когда данные пришли в виде сводной таблицы, а вам нужны строки.

# Широкий формат: столбцы jan, feb, mar с выручкой
df_long = df.melt(
    id_vars=['city'],
    value_vars=['jan', 'feb', 'mar'],
    var_name='month',
    value_name='revenue'
)

Результат: вместо трёх столбцов-месяцев — два столбца month и revenue, строк стало в три раза больше.

На собеседовании: просят привести данные к «нормальной форме» — это и есть melt. Обратная операция (из длинного в широкий) — pivot_table или pivot.

Работа с датами

На собеседованиях часто дают данные с датами и просят посчитать метрику по дням, неделям или месяцам. Pandas умеет это из коробки.

Преобразование в datetime

df['date'] = pd.to_datetime(df['date'])

# Формат указан явно
df['date'] = pd.to_datetime(df['date'], format='%d.%m.%Y')

Если не преобразовать столбец в datetime, все операции с датами будут выдавать ошибки или неверные результаты. Это первое, что нужно сделать после загрузки.

Аксессор dt

Доступ к компонентам даты:

df['year'] = df['date'].dt.year
df['month'] = df['date'].dt.month
df['weekday'] = df['date'].dt.day_name()
df['week'] = df['date'].dt.isocalendar().week

resample

Агрегация временных рядов по периодам. Работает только с DatetimeIndex.

df = df.set_index('date')

# Дневная выручка → недельная
weekly = df['revenue'].resample('W').sum()

# Месячное среднее DAU
monthly_dau = df['dau'].resample('ME').mean()

Периоды: 'D' — день, 'W' — неделя, 'ME' — месяц, 'QE' — квартал.

Альтернатива без DatetimeIndex — pd.Grouper:

df.groupby(pd.Grouper(key='date', freq='ME'))['revenue'].sum()

Делает то же самое, но не требует менять индекс.

apply, map, transform

apply

Применяет функцию к каждой строке или столбцу.

# Категоризация чека
def size_category(amount):
    if amount > 5000:
        return 'large'
    elif amount > 1000:
        return 'medium'
    return 'small'

df['size'] = df['amount'].apply(size_category)

apply — мощный, но медленный инструмент. Для простых операций используйте векторные методы:

# Вместо apply — np.where (быстрее в десятки раз)
import numpy as np
df['is_big'] = np.where(df['amount'] > 5000, True, False)

map

Замена значений по словарю:

status_map = {'new': 'Новый', 'completed': 'Завершён', 'cancelled': 'Отменён'}
df['status_ru'] = df['status'].map(status_map)

transform

Как apply, но возвращает результат того же размера, что и исходный DataFrame. Удобен с groupby:

# Доля каждого заказа от суммы по пользователю
df['user_total'] = df.groupby('user_id')['amount'].transform('sum')
df['share'] = df['amount'] / df['user_total']

Аналог оконной функции SUM() OVER (PARTITION BY user_id) в SQL.

Частые паттерны

Скользящее среднее (rolling)

df['revenue_7d'] = df['revenue'].rolling(window=7).mean()

Аналог AVG() OVER (ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) в SQL. Первые 6 строк будут NaN — окно ещё не заполнилось.

Нарастающий итог (cumsum)

df['cumulative_users'] = df['new_users'].cumsum()

Аналог SUM() OVER (ORDER BY date) в SQL. Работает корректно, если данные отсортированы по дате — иначе результат будет бессмысленным.

Лаг (shift)

# Выручка за предыдущий день
df['prev_day'] = df['revenue'].shift(1)

# Изменение день к дню
df['daily_change'] = df['revenue'] - df['revenue'].shift(1)

# Процентное изменение
df['pct_change'] = df['revenue'].pct_change()

shift(1) — аналог LAG(revenue, 1) в SQL. shift(-1) — аналог LEAD.

Ранжирование

# Ранг по выручке внутри каждого города
df['rank'] = df.groupby('city')['revenue'].rank(ascending=False, method='dense')

Параметр method: 'min' = RANK(), 'dense' = DENSE_RANK(), 'first' = ROW_NUMBER(). Подробнее об оконных функциях SQL и их pandas-аналогах — в шпаргалке по оконным функциям.

Что спрашивают на собеседованиях

Типовые задачи на pandas, которые встречаются на интервью аналитиков:

  1. Посчитайте retention D1 на pandas. Нужно найти дату первого визита каждого пользователя (groupby + min), затем merge с таблицей активности и проверить, был ли визит на следующий день.

  2. Объедините две таблицы и найдите пользователей без заказов. Left merge + фильтрация по NaN в столбце из правой таблицы.

  3. Посчитайте скользящее среднее выручки за 7 дней. rolling(7).mean() после сортировки по дате.

  4. Найдите топ-3 товара по выручке в каждой категории. groupby + apply с nlargest, или rank + фильтрация.

  5. Переведите данные из широкого формата в длинный. melt с указанием id_vars и value_vars.

  6. Чем merge отличается от join? merge — по значениям столбцов (аналог SQL JOIN). join — по индексу. На практике merge используется чаще.

Больше задач по Python — в разделе подготовки. SQL-аналоги тех же операций — в разделе SQL.

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

Pandas нужно писать руками. Прочитать шпаргалку недостаточно — через неделю в голове останется только import pandas as pd. Навык формируется, когда вы решаете задачи: фильтруете, группируете, джойните, считаете метрики.

Тренажёр Карьерник содержит задачи по Python и pandas с разборами — от базовых операций до продвинутых паттернов с groupby и merge. Можно тренироваться по 15 минут в день в Telegram: этого достаточно, чтобы к собеседованию операции стали автоматическими.

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

FAQ

Pandas или SQL — что учить первым?

SQL. Он проще, его спрашивают на каждом собеседовании, и большинство аналитических задач решаются именно в SQL. Pandas нужен как второй инструмент — для случаев, когда данные уже выгружены, нужна сложная трансформация или визуализация. На практике аналитик использует оба: SQL для запросов к базе, pandas для обработки результатов.

Что быстрее — pandas или SQL?

Для данных, которые помещаются в оперативную память (до нескольких ГБ), pandas и SQL сравнимы по скорости. Для больших объёмов SQL на сервере базы данных быстрее, потому что запрос выполняется на стороне СУБД с оптимизатором запросов, индексами и параллелизмом. Pandas загружает всё в память одного процесса. Если данные не помещаются в RAM, pandas упадёт — SQL продолжит работать.

Как запомнить синтаксис merge, если путаюсь в параметрах?

Запомните одну конструкцию: left.merge(right, on='key', how='left'). Это покрывает 80% случаев. Когда ключи называются по-разному — left_on и right_on. Когда нужно все строки из обеих таблиц — how='outer'. Остальное — вариации этого шаблона.