Pandas отчет о продажах

В качестве источника данных используется — https://www.kaggle.com/carrie1/ecommerce-data.

Для начала подключается Pandas и вычитывается файл:

import pandas as pd

df = pd.read_csv('ecommerce-data.zip',encoding = "cp1252")
df.head()

Теперь нужно найти пустые данные в датасете:

df.isna().mean()

Обратите внимание, что есть пустые значения в CustomerID. К сожалению метод groupby игнорирует NaN, поэтому давайте заполним его отрицательными значениями, чтобы сохранить числовой тип данных:

df['CustomerID'].fillna(-999,inplace=True)

И сразу конвертируем дату в дату питона (если pandas будет выдавать ошибки, вот здесь еще есть способы конвертации даты):

df['InvoiceDate'] = pd.to_datetime(df['InvoiceDate'],format='%m/%d/%Y %H:%M')

Давайте посмотрим какой минимальный и максимальный период представлен в датасете:

df['InvoiceDate'].min()

Timestamp (‘2010–12–01 08:26:00’)

df['InvoiceDate'].max()

Timestamp (‘2011–12–09 12:50:00’)

В датасете представлен примерно 1 год. Теперь давайте подготовим месячный отчет о продажах

1. Создание таблицы с уникальными пользователями

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

user = df.groupby(['CustomerID'])['InvoiceDate'].min().reset_index()
user.head()

Переименуем колонки:

user.columns = ['CustomerID','reg_date']

Отдельно добавим месяц регистрации:

user['reg_month'] = user['reg_date'].values.astype('datetime64[M]')

Результат:

user

2. Создадим шаблонную таблицу с каждым возможным месяцем для каждого пользователя:

min_month = df['InvoiceDate'].values.astype('datetime64[M]').min()
max_month = df['InvoiceDate'].values.astype('datetime64[M]').max()
dr = pd.DataFrame(pd.date_range(min_month,max_month,freq='MS'))
dr.columns = ['month']

Сделаем перекрестное соединение с таблицей пользователей и получить

len(user)*len(dr)

строк. В pandas это можно сделать следующим образом:

dr['key'] = 1
user['key'] = 1
report = dr.merge(user,on='key')
report.head()

Проверим сколько строк получилось в новом датасете:

len(report)

Как и ожидалось 56849.

Но есть несколько лишних строк: некоторые пользователи пришли намного позже минимальной даты (2010-12), и глупо иметь записи для пользователя до того, как он пришел к нам).

report = report[report['month']>=report['reg_month']]

Давайте посмотрим на конкретного пользователя, просто чтобы проверить правильность.

report[report['CustomerID'] == 12346.0]

и еще:

report[report['CustomerID'] == 12448.0]

Теперь можно объеденить данные о продажах с датасетом пользователей. Прежде чем сделать это, нужно провести некоторую подготовку.

3. Предварительная агрегация данных.

Произведем расчет по общему объему продаж за каждый месяц для каждого клиента.

df['month'] = df['InvoiceDate'].values.astype('datetime64[M]')
df['revenue'] = df['UnitPrice'] * df['Quantity']
sales_month = df.groupby(['CustomerID','month'])[['revenue']].agg('sum').reset_index()
sales_month.head()

При создании новых таблиц всегда нужно следить за тем, чтобы итоговые суммы совпадали!

df['revenue'].sum()

9747747.933999998

sales_month['revenue'].sum()

9747747.934000025

4. Объеденение

Очень важно использовать LEFT JOIN! С помощью LEFT JOIN будут сохранены все строки — таким образом можно увидеть когда клиенты были активны, а когда нет:

report = report.merge(sales_month,how='left',on=['CustomerID','month'])
report.head()

Проверить итоговые показатели:

df['revenue'].sum()

9747747.933999998

report['revenue'].sum()

9747747.934000023

Отлично! Теперь еще одна проверка по клиенту:

report[report['CustomerID'] == 12347.0]

Видно, что активность этого клиента не является регулярной. К примеру после 2011-01-01 наблюдается пауза в покупках в течение двух месяцев. Затем закупки начинаются снова.

5. Базовые метрики

Добавить общее количество активных и новых пользователей:

report['user'] = 1
report['new'] = (report['reg_month'] == report['month']) * 1
report['active'] = (report['revenue'] > 0) * 1
report.head()

Теперь можно создать ежемесячный отчет на основе этой таблицы:

report.groupby('month')[['revenue','user','new','active']].agg('sum')

Это очень надежный способ создания всех видов отчетов: ежедневных, еженедельных, ежемесячных.

Сразу стоит оговориться, что подобные отчеты удобнее делать через SQL, он намного мощнее. Но, если у вас нет знаний SQL и вам никто не дает доступы к базе данных, а просто делает выгрузки — PANDAS один из луших инструментов для быстрого анализа. В примере отчет делается в Jupiter