EDA в pandas: как провести разведывательный анализ данных
Пошаговый EDA в pandas: проверить структуру, распределения, связи и сегменты до того, как строить метрики и делать выводы.
Содержание статьи
Разведывательный анализ нужен до красивого дашборда и до сложной модели. Он помогает понять, что именно лежит в таблице, где данные неполные, какие значения типичны и какие сегменты ведут себя иначе. EDA не даёт автоматического ответа, но заметно снижает риск считать не то.
Коротко
EDA — это короткое исследование формы данных: размер, типы, пропуски, уникальность, распределения, связи и сегменты. Его результатом должен быть список наблюдений и вопросов для следующего анализа, а не коллекция случайных графиков.
- Начни с зерна таблицы и периода данных.
- Смотри на распределение, а не только на среднее.
- Отделяй технические пропуски от реального отсутствия значения.
- Проверяй ключевые срезы до общего вывода.
Шаг 1. Профиль таблицы
Первый экран EDA должен отвечать на простые вопросы: сколько строк, какие поля, какой диапазон дат, где пропуски и сколько уникальных ключей. Если в таблице заказов 200 тысяч строк, но только 80 тысяч order_id, это уже влияет на любой последующий расчёт.
def profile(df: pd.DataFrame) -> pd.DataFrame:
return pd.DataFrame({
'dtype': df.dtypes.astype(str),
'missing': df.isna().sum(),
'missing_share': df.isna().mean().round(3),
'unique': df.nunique(dropna=False),
}).sort_values('missing_share', ascending=False)
print('rows, columns:', orders.shape)
display(profile(orders))
display(orders[['created_at', 'revenue']].describe())Шаг 2. Смотреть на распределения
Средний чек может быть 1 500 ₽, хотя половина заказов меньше 600 ₽, а несколько крупных клиентов тянут среднее вверх. Поэтому для денег и времени полезно смотреть медиану, квантили и хвост. Выброс — не всегда ошибка: иногда это отдельный тип пользователя или важный бизнес-сценарий.
| Показатель | Что показывает | Осторожность |
|---|---|---|
| median | типичное центральное значение | не показывает размер хвоста |
| quantile(0.9) | уровень, ниже которого 90% наблюдений | зависит от размера выборки |
| min / max | границы наблюдаемых значений | часто чувствительны к ошибкам |
| std | разброс вокруг среднего | плохо объясняет сильно асимметричные данные |
revenue_summary = orders['revenue'].describe(percentiles=[.5, .75, .9, .99])
print(revenue_summary)
p99 = orders['revenue'].quantile(.99)
large_orders = orders.loc[orders['revenue'] > p99]
print('share of orders above p99:', len(large_orders) / len(orders))Шаг 3. Сегменты важнее общей средней
Общий показатель может быть устойчивым, пока внутри него меняются сегменты. Средний заказ по всем каналам скрывает разницу между новым и возвращающимся покупателем. EDA помогает найти срезы, где меняется форма данных, а затем уже решать, нужен ли отдельный KPI или дополнительная гипотеза.
segment_summary = (
orders.groupby('channel')
.agg(
orders=('order_id', 'nunique'),
buyers=('user_id', 'nunique'),
median_revenue=('revenue', 'median'),
p90_revenue=('revenue', lambda s: s.quantile(.9)),
)
.sort_values('median_revenue', ascending=False)
)
display(segment_summary)EDA не доказывает причину
Если пользователи из referral-канала покупают чаще, это ещё не означает, что канал сам по себе создаёт лучший опыт. В него могли попадать более лояльные клиенты или другой тип продукта. Разведывательный анализ формирует вопрос: “почему сегмент отличается?”. Для причинности нужны эксперимент, квазиэксперимент или дополнительный дизайн исследования.
- Не удаляй выбросы только ради более красивого среднего.
- Не называй корреляцию влиянием.
- Запиши, какие фильтры применил к исследованию.
- Отделяй находки, которые увидел заранее, от найденных перебором срезов.
Сформулируй карту вопросов до просмотра графиков
EDA легко превращается в бесконечное листание диаграмм. Чтобы этого не произошло, раздели вопросы на четыре группы: полнота данных, распределение, сегменты и время. Сначала проверь, все ли пользователи и периоды попали в набор. Затем посмотри форму ключевых числовых полей. Только после этого переходи к сравнениям.
Для каждой находки записывай статус: факт, гипотеза или вопрос для проверки. Например, «Android revenue ниже» — факт описательного среза. «На Android проблема в оплате» — гипотеза. «Есть ли ошибка после версии 4.2?» — следующий вопрос. Такая маркировка не даёт EDA незаметно превратиться в причинный вывод.
Сохраняй фильтры и размер выборки рядом с графиком. Если ты посмотрел только платящих пользователей, вывод нельзя переносить на всю аудиторию. Порядок исследования тоже важен: найденная после двадцати срезов разница требует подтверждения на отдельной выборке или в заранее заданном анализе.
| Слой | Вопрос | Пример проверки |
|---|---|---|
| полнота | есть ли все строки и периоды | диапазон дат и объём по дням |
| форма | как распределено значение | квантили, выбросы, пропуски |
| сегменты | где группы отличаются | platform, channel, plan |
| время | когда появилась разница | тренд и точка изменения |
Пропуски и выбросы нужно описать, а не спрятать
Доля пропусков — только начало. Важно понять, какие строки пропущены: один канал, один день, новый тип устройства или случайный набор. Сравнивай missingness по сегментам и времени. Если revenue отсутствует только после релиза, это уже сигнал о контракте события, а не повод заполнить все значения средним.
Выбросы могут быть ошибкой, крупным клиентом или редким, но важным сценарием. До удаления посмотри исходную строку и влияние на метрику. Для среднего полезно показать медиану и квантили рядом, а для бизнеса — отдельно посчитать результат с и без спорного сегмента. Это честнее, чем незаметно обрезать верхний процент.
Нормализация масштаба тоже влияет на вывод. Два канала могут иметь одинаковое среднее, но совершенно разную дисперсию. Boxplot или таблица p50/p90/p99 помогает понять, одинаков ли пользовательский опыт или его портит небольшой хвост.
profile = pd.DataFrame({
'missing_share': orders.isna().mean(),
'unique_values': orders.nunique(dropna=False),
})
revenue_stats = orders['revenue'].quantile([.5, .9, .99])
print(profile.sort_values('missing_share', ascending=False))
print(revenue_stats)Сегменты: сравни не только средние
Разница между сегментами может возникнуть из-за состава. Сравнивай размер группы, долю пропусков, период наблюдения и распределение ключевого показателя. Если одна группа в два раза меньше, один крупный пользователь способен изменить среднее. Для первой проверки используй медиану, квантили и доверительный интервал, а не только одно число.
Не строй сразу двадцать разрезов и не выбирай самый красивый. Сначала выбери сегмент по продуктовой гипотезе, затем один независимый разрез для проверки устойчивости. Если эффект появляется только в одном из двадцати случайных срезов, это повод для осторожности, а не для заголовка отчёта.
Кросс-сегментация помогает найти составной эффект, но быстро уменьшает базу. Подписывай размер каждой ячейки и объединяй редкие категории, если это соответствует смыслу. Пустая или очень маленькая ячейка не даёт права на сильный вывод.
После каждого сигнала запиши, какие данные или эксперимент смогут его подтвердить. Не превращай визуальную корреляцию в готовое решение.
Практика: закончить EDA коротким memo
Финал EDA — не папка из двадцати графиков, а короткое memo. В нём должны быть размер и период источника, три устойчивых наблюдения, две гипотезы, ограничения и следующий шаг. Для каждого наблюдения приложи ссылку на таблицу или код, из которого оно получено.
Отдельно перечисли, что ты не проверял: причинность, сезонность, качество трекинга или влияние маркетингового состава. Это не ослабляет исследование. Наоборот, команда понимает границы и не использует описательный срез как доказательство эффекта.
Если EDA повторяется еженедельно, преврати стабильные проверки в функции или SQL-контроль. Исследовательская часть может оставаться интерактивной, а профиль источника и sanity-check должны запускаться одинаково.
- Начать с полноты и схемы источника.
- Посмотреть пропуски, квантили и выбросы.
- Сравнить сегменты с размером базы.
- Разделить факт, гипотезу и следующий вопрос.
- Закончить memo с ограничениями и действием.
Материалы по теме

Как тестировать аналитические расчёты на Python и pandas
Практический гайд по тестам для аналитика: проверить метрики на маленьком датасете, поймать регрессию и защитить расчёт от тихих изменений.

Как ускорить pandas: память, типы и обработка больших файлов
Что делать, если pandas медленно работает или не помещает файл в память: категории, downcast, chunksize, Parquet и контроль размера данных.

Pandas apply и векторизация: как писать быстрее и понятнее
Когда использовать apply, почему векторные операции быстрее и как переписать медленный построчный расчёт в pandas.