0.2 pandas: загрузка, фильтрация, merge, groupby и даты

Урок 0.2. pandas: таблицы в Python

После урока вы сможете:

  • загружать CSV и быстро изучать таблицу;
  • выбирать столбцы и фильтровать строки;
  • находить и заполнять пропуски;
  • объединять таблицы через merge и группировать через groupby;
  • извлекать час, день недели и другие признаки из дат.

Загрузка и первый взгляд

pandas — главная библиотека для работы с таблицами в Python. Таблица в pandas называется DataFrame, отдельный столбец — Series.

import pandas as pd

orders = pd.read_csv('orders.csv', parse_dates=['order_datetime'])   # сразу распознаём даты
menu_df = pd.read_csv('menu.csv')

orders.shape       # (4000, 7) — строк и столбцов
orders.head()      # первые 5 строк
orders.info()      # типы столбцов и число непустых значений
orders.describe()  # статистики по числовым столбцам

Эти четыре команды — первое, что делает аналитик с любыми новыми данными. Вы будете запускать их в начале каждого модуля.

Выбор и фильтрация

Задача pandas SQL
Один столбец orders['branch'] SELECT branch
Несколько столбцов orders[['branch', 'quantity']] SELECT branch, quantity
Фильтр orders[orders['quantity'] >= 3] WHERE quantity >= 3
Два условия orders[(условие1) & (условие2)] WHERE … AND …
Подсчёт значений orders['branch'].value_counts() GROUP BY branch … COUNT(*)
# Заказы в Оше, где взяли 3 и больше позиций
big_osh = orders[(orders['branch'] == 'Ош') & (orders['quantity'] >= 3)]
len(big_osh)     # 138

Каждое условие — в скобках, и между ними & (И) или | (ИЛИ). Слова and и or в фильтрах pandas не работают и вызывают ошибку.

Пропуски

orders.isna().sum()      # payment_method: 69 пропусков
orders['payment_method'] = orders['payment_method'].fillna('Не указано')
orders['payment_method'].value_counts(normalize=True)   # доли вместо количества

Половина заказов (51%) оплачивается через QR, 29% — картой и только 18% — наличными. У 1,7% заказов способ оплаты не записан.

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

В заказах есть только номер позиции. Название, категория, цена и себестоимость — в меню. merge делает то же, что JOIN в SQL:

df = orders.merge(menu_df, on='item_id', how='left')     # LEFT JOIN по item_id

# Новые столбцы считаются сразу для всей таблицы
df['revenue'] = df['quantity'] * df['price_som']
df['profit'] = df['quantity'] * (df['price_som'] - df['cost_som'])

Группировка: groupby

by_item = (df.groupby('item_name')
             .agg(orders=('order_id', 'count'),
                  revenue=('revenue', 'sum'),
                  profit=('profit', 'sum'))
             .sort_values('revenue', ascending=False))
by_item['margin_pct'] = (by_item['profit'] / by_item['revenue'] * 100).round(1)
Позиция Заказов Выручка, сом Маржа
Капучино 607 193 800 71,1%
Латте 478 166 320 71,4%
Раф 292 116 880 70,8%
Чизкейк 270 113 880 57,7%
… … … …
Чай с чабрецом 245 53 040 80,8%

Что узнал владелец «Ала-Арча Кофе»: капучино и латте — главные источники выручки. Самая высокая маржа — у чая (около 80%), но его заказывают реже. Десерты и выпечка дают 58–67% маржи. Идея для меню: комбо «десерт + чай» поднимет среднюю маржу чека. Точка «Центр» приносит больше трети выручки сети — 383 тысячи сомов за два месяца.

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

Из даты и времени можно извлечь много полезных признаков. В машинном обучении это частый приём.

df['date'] = df['order_datetime'].dt.date
df['hour'] = df['order_datetime'].dt.hour
df['weekday'] = df['order_datetime'].dt.dayofweek     # 0 — понедельник, 6 — воскресенье
df['is_weekend'] = (df['weekday'] >= 5).astype(int)

Средняя выручка сети в будний день — около 18 200 сомов, в выходной — около 18 000. Выходные почти не отличаются от будней.

Задание для самопроверки: найдите точку с самой высокой средней суммой заказа. Подсказка: в данных одна строка — один заказ. Решение — в конце ноутбука.

Итоги урока

  • head, info, describe — первый взгляд на любые данные.
  • Фильтры пишутся через & и |, каждое условие — в скобках.
  • merge — это JOIN, groupby + agg — это GROUP BY.
  • Через .dt из дат извлекаются час, день недели и выходные.