Мира · маркетолог магазина настолок «Кубик»
Мы работаем полтора года, данных накопилось много, а я так и не знаю, что в них лежит. Посмотри всё свежим взглядом: кто, что и когда у нас покупает. И принеси идеи, что проверить дальше, а не только цифры.
В боссе блока D мы отвечали Мире на три конкретных вопроса: кто покупает, какие промокоды окупаются и кто лучшие клиенты. Сегодня вопроса нет, есть данные. Такое исследование называют разведочным анализом, или EDA. Его результат не ответ, а список хороших вопросов с цифрами.
Работаем в pandas и идём тремя фазами, как в боссах: профиль данных, распределения и связи, гипотезы. Портрет клиента и маржу промокодов из босса 31 не пересчитываем, а опираемся на них.
Фаза 1. Профиль данных
Мира выгрузила из админки таблицы в CSV. Если доступ к базе у тебя есть, те же таблицы достаются запросом прямо из Python, как в уроке про SQL из Python. Начинаем с вопроса «сколько чего»:
import pandas as pd
customers = pd.read_csv("customers.csv")
orders = pd.read_csv("orders.csv")
customers.shape, orders.shape # ((3534, 4), (6555, 6))
| Таблица | Строк | Что в ней |
|---|---|---|
customers | 3534 | аккаунт: почта, город, канал привлечения |
orders | 6555 | заказ: покупатель, статус, день, промокод, сумма позиций и возвратов |
order_items | 11 283 | позиции заказов |
products | 122 | игры: жанр, цена, себестоимость |
returns | 273 | возвраты |
deliveries | 6597 | попытки доставки |
visits | 19 361 | визиты на сайт с UTM-метками |
В orders.csv Мира уже свела сумму позиций (items_rub) и сумму возвратов (refund_rub) на уровень заказа, так что таблица одна, а не три.
Профиль столбцов
Дальше по каждому столбцу три вопроса: какой тип, сколько пропусков, сколько разных значений. info() из урока про чистку отвечает на первые два, но удобнее собрать ответ в одну таблицу. Такую таблицу называют профилем данных. Функцию profile(df) ты соберёшь в первом квесте, а вот что она показывает на заказах:
dtype missing missing_pct unique
customer_id int64 0 0.0 3038
status object 0 0.0 4
order_date object 0 0.0 546
promo_code object 4520 69.0 9
items_rub int64 0 0.0 1825
refund_rub int64 0 0.0 153
Читаем сверху вниз. order_date пришёл строкой: даты надо разобрать, иначе месяц из них не достать. В promo_code 69% пусто, но это не дыра в данных: пусто значит «без промокода». Такой пропуск несёт смысл, и заполнять его нельзя. Аккаунтов с заказами 3038, а в customers их 3534: 496 аккаунтов не сделали ни одного заказа. У клиентов профиль находит пропуски в городе: 94 аккаунта, 2,7%.
Двойники
В профиле клиентов у email 3534 разных значения, ровно по числу строк. Дублей нет? Сравним почту без учёта регистра:
customers["email"].duplicated().sum() # 0
customers["email"].str.lower().duplicated().sum() # 19
19 человек завели второй аккаунт, набрав почту с заглавной буквы. Эту болячку мы уже лечили в SQL через lower(email). В pandas лечение то же: человек это почта в нижнем регистре, а не id.
Диапазоны дат
Заказы идут с 1 января 2025 по 30 июня 2026: полтора года, ровно один декабрь. Это пригодится в фазе 2. Ещё одна проверка дат: заказ не может случиться раньше регистрации. Проверим в песочнице на полной базе:
SQL-песочница
База · boardshop
База загрузится, когда ты выполнишь запрос или откроешь таблицы.
Выполни запрос, чтобы увидеть результат.
Выбери доступную таблицу для просмотра данных и структуры.
Выбери доступную таблицу для просмотра данных и структуры.
Выполни весь запрос кнопкой или Ctrl/Cmd+Enter. Ctrl+Space открывает подсказки. Можно писать несколько команд через точку с запятой, менять данные и открывать транзакции. У каждой песочницы своя база, изменения живут до ухода со страницы. «Сбросить базу» возвращает учебные данные, но не меняет SQL.
Таких заказов 271, и все в тот же день, что регистрация, самое большое расхождение 15 часов 26 минут. Похоже, время регистрации пишет одна система, а время заказа другая. На анализ по дням это не влияет, а вот «время от регистрации до первой покупки» в часах считать нельзя. Причину мы не знаем, поэтому записываем вопрос разработчикам и идём дальше.
Аномалии и правила чистки
orders["status"].value_counts()
delivered 6136
cancelled 364
shipped 43
new 12
364 заказа отменены. shipped и new это заказы последних дней, они ещё едут, их оставляем. Возвраты есть у 273 заказов на 600 525 ₽, и 147 из них вернули целиком. Из 122 игр каталога 4 не продались ни разу.
Из профиля получаются правила, по которым строим чистую таблицу для фазы 2:
- отменённые заказы убираем, это не покупки;
- людей узнаём по почте в нижнем регистре;
- сумма заказа считается после возвратов,
items_rub - refund_rub; - пустой промокод значит «без промокода».
Получается 6191 заказ, 2927 человек и 21 274 258 ₽. Те же числа дал SQL в боссе 31, значит, pandas и база сходятся.
урок из курса
Урок из курса «Аналитика данных с нуля». Курс покупается один раз и остаётся навсегда: 500 ₽.
Оплата пока не подключена: премиум и курсы открываются промокодом.