Привет! Продолжем изучать Pandas. В прошлый раз я рассказал о возможностях библиотеки, а сегодня покажу, как с её помощью делать когортный анализ.
Прежде всего, вспомним, что такое когорты и как их анализировать.
Когорта — это группа людей, которая совершила нужное действие в определенный промежуток времени.
Когортный анализ — это наблюдение за когортами. Выбираем одну или несколько метрик, измеряем их и делаем выводы.
Например, социологи могут отслеживать, сколько людей, родившихся в 1980 году, получили высшее образование. Когорта здесь — те, кто родились в 1980 году. Метрика — доля людей с высшим образованием.
Еще пример: маркетологи хотят узнать, сколько заказов и выручки принесли пользователи, совершившие свой первый заказ год назад. Теперь когорта — это прошлогодние покупатели, а метрики — количество заказов и выручка.
Получается, когортный анализ состоит из трех шагов: определения нужного действия и временного промежутка когорты и выбора метрик для отслеживания:
Действие | Время | Метрика |
---|---|---|
Родились | В 1980 году | % людей с высшим образованием |
Впервые |
Год назад | Количество заказов и выручка |
Установили приложение | Неделю назад | % пользователей, открывших приложение еще раз |
Когорты можно сравнивать между собой. Например, маркетологи измеряют, сколько заказов обычно делают пользователи в течение месяца после первой покупки и смотрят динамику:
Месяц | Клиенты | Покупок в 1й месяц | Покупок на клиента |
---|---|---|---|
Январь 2018 | 134 | 161 | 1.20 |
Февраль 2018 | 164 | 194 | 1.18 |
Март 2018 | 193 | 200 | 1.03 |
Общее количество клиентов и покупок выросло — приятно. Но, сравнив когорты, видим, что в среднем клиенты стали покупать реже — тревожный знак.
Ок, теперь мы готовы к тому, чтобы научиться делать когортный анализ с помощью Pandas. Для наглядности решим задачу.
Задача
Допустим, мы работаем в
>>> orders.head() | |
order_date ship_mode customer_id sales | |
id | |
100006 2014-09-07 Standard DK-13375 377.970 | |
100090 2014-07-08 Standard EB-13705 699.192 | |
100293 2014-03-14 Standard NF-18475 91.056 | |
100328 2014-01-28 Standard JC-15340 3.928 | |
100363 2014-04-08 Standard JM-15655 21.376 |
Каждая строка таблицы orders
— это покупка. Мы знаем, когда она произошла, кто её сделал и сколько денег она принесла в магазин. Дата заказа лежит в поле order_date
, номер покупателя — в customer_id
, а выручка — в sales
.
Часто бывает, что даты загружаются в виде текста. Преобразим колонку order_date
из текста в дату:
>>> orders['order_date'] = pd.to_datetime(orders['order_date']) |
Данные перед нами, теперь можно с ними работать. Начнем с простого: выясним, сколько всего в магазине было покупок и выручки.
Считаем покупки и выручку
Чтобы посчитать общую выручку, просуммируем колонку sales
:
>>> orders['sales'].sum() | |
2297200.8603000003 |
Количество заказов можно посчитать с помощью этой же колонки, но вместо суммы используем метод count()
:
>>> orders['sales'].count() | |
5009 |
Теперь посчитаем обе метрики для каждого пользователя. Сгруппируем датафрейм по полю customer_id
:
>>> orders.groupby('customer_id')['sales'].agg(['sum', 'count']) | |
sum count | |
customer_id | |
AA-10315 5563.5600 5 | |
AA-10375 1056.3900 9 | |
AA-10480 1790.5120 4 | |
AA-10645 5086.9350 6 | |
AB-10015 886.1560 3 | |
AB-10060 7755.6200 8 | |
AB-10105 14473.5710 10 | |
... |
Видим, например, что пользователь AA-10315 сделал 5 заказов и принес $5563 выручки.
Идём дальше. Чтобы построить когорты, нам нужно сгруппировать клиентов по дате их первой покупки. В данных нет такого поля, значит, нужно его посчитать.
Считаем дату первой покупки
Чтобы вычислить дату первой покупки каждого пользователя, сгруппируем данные по customer_id
и найдем минимальное значение поля order_date
. Результат сохраним в переменную first_orders
:
>>> first_orders = orders.groupby('customer_id')['order_date'].agg({'first_order': 'min'}) | |
>>> first_orders.head() | |
first_order | |
customer_id | |
AA-10315 2014-03-31 | |
AA-10375 2014-04-21 | |
AA-10480 2014-05-04 | |
AA-10645 2014-06-22 | |
AB-10015 2014-02-18 |
Видим, что пользовать AA-10315 впервые что-то купил 31 марта 2014 года, а пользователь AA-10375 — 21 апреля того же года.
Зная даты первых покупок, можем строить когорты.
Строим когорты
Итак, когортами будем считать людей, сделавших первую покупку в тот или иной день. Метрики для отслеживания — количество заказов и выручка.
План такой: сначала добавим дату первой покупки пользователей в таблицу с заказами, затем сгруппируем по датам первой покупки и заказа и, наконец, посчитаем выручку и количество заказов каждой когорты.
Приступим. Добавим дату первой покупки с помощью метода merge()
и сохраним получившийся датафрейм в переменную orders_merged
:
>>> orders_merged = orders.merge(first_orders, how='inner', left_on='customer_id', right_index=True) | |
>>> orders_merged.head() | |
order_date ship_mode customer_id sales first_order | |
id | |
100006 2014-09-07 Standard DK-13375 377.970 2014-09-07 | |
131884 2015-12-06 Same Day DK-13375 594.002 2014-09-07 | |
145065 2015-12-12 First DK-13375 32.308 2014-09-07 | |
133046 2017-07-27 Second DK-13375 297.990 2014-09-07 | |
165099 2017-12-11 First DK-13375 1.392 2014-09-07 |
В строках получившегося датафрейма всё еще покупки, но теперь в таблице появилась новая колонка: дата первой покупки пользователя.
Агрегируем по дате первой покупки и посчитаем нужные показатели:
>>> orders_merged.groupby('first_order')['sales'].agg(['sum', 'count']) | |
sum count | |
first_order | |
2014-01-03 1050.6360 9 | |
2014-01-04 1056.8580 5 | |
2014-01-05 1428.2310 7 | |
2014-01-06 14287.5570 22 | |
2014-01-07 1055.9810 4 | |
2014-01-09 370.3480 4 | |
2014-01-10 4867.3440 7 | |
... |
Видим, что клиенты от 3 января 2014 года, всего сделали 9 заказов на $1050.6. Посмотрим, когда были эти заказы. Для этого добавим к группировке колонку order_date
:
>>> orders_merged.groupby(['first_order','order_date'])['sales'].agg(['sum', 'count']) | |
sum count | |
first_order order_date | |
2014-01-03 2014-01-03 16.448 1 | |
2014-11-12 153.112 1 | |
2015-04-18 209.550 1 | |
2015-11-24 383.610 1 | |
2016-05-15 7.764 1 | |
2016-11-14 37.630 1 | |
2017-03-04 89.568 1 | |
2017-05-14 87.994 1 | |
2017-08-26 64.960 1 | |
2014-01-04 2014-01-04 288.060 1 | |
2015-09-25 183.400 1 | |
2015-11-20 344.372 1 | |
2015-11-29 4.304 1 | |
2017-10-05 236.722 1 |
Ага, первый заказ этой когорты был 3 января на $16. В следующий раз клиент вернулся почти год спустя и купил что-то ещё, в этот раз на $153. Следующая покупка была уже в апреле 2015 и так далее.
Когорты готовы, теперь решим задачу.
Решаем задачу
Напомню, что мы хотим посчитать, сколько в среднем заказов и выручки приносят клиенты в течение года, после первой покупки.
Мы знаем, сколько магазин заработал с каждой когорты за всё время. Уточним метрику: посчитаем показатели за первый год жизни когорты.
Сначала узнаем, сколько дней прошло между первой покупкой и последующим заказом, и удалим те, которые случились позже 365 дней. Чтобы посчитать количество дней между заказами, вычтем из колонки order_date
столбец first_order
:
>>> orders_merged['order_date'] - orders_merged['first_order'] | |
id | |
100006 0 days | |
131884 455 days | |
145065 461 days | |
133046 1054 days | |
165099 1191 days | |
166835 1162 days | |
111290 684 days | |
139087 679 days | |
... |
Вуаля. Видим, что, например, заказ 131884
случился 455 дней спустя первой покупки. 455 days
— это тип данных под названием «Timedelta», его специально придумали, чтобы показывать временные промежутки.
Чтобы удалить поздние заказы, добавим условие <= '365 days'
:
>>> orders_merged['order_date'] - orders_merged['first_order'] <= '365 days' | |
id | |
100006 True | |
131884 False | |
145065 False | |
133046 False | |
165099 False | |
166835 False | |
111290 False | |
139087 False | |
... |
Сохраним результат в переменную year_1_filter
, отфильтруем ненужные заказы из когортного отчета и сохраним результат в переменную year_1_orders
:
>>> year_1_filter = orders_merged['order_date'] - orders_merged['first_order'] <= '365 days' | |
>>> year_1_orders = orders_merged[year_1_filter] | |
>>> year_1_orders.head() | |
order_date ship_date ship_mode customer_id sales first_order | |
id | |
CA-2014-100006 2014-09-07 2014-09-13 Standard Class DK-13375 377.970 2014-09-07 | |
CA-2014-100090 2014-07-08 2014-07-12 Standard Class EB-13705 699.192 2014-07-08 | |
CA-2014-129938 2014-12-15 2014-12-17 Second Class EB-13705 445.802 2014-07-08 | |
CA-2015-128125 2015-03-31 2015-04-05 Standard Class EB-13705 120.756 2014-07-08 | |
CA-2014-100293 2014-03-14 2014-03-18 Standard Class NF-18475 91.056 2014-03-14 |
В датафрейме остались только заказы, сделанные когортами в первый год после первой покупки. Теперь сгруппируем заказы по дате первой покупки и посчитаем нужные метрики. Результат сохраним в переменную cohorts
:
>>> cohorts = year_1_orders.groupby(['first_order','order_date'])['sales'].agg(['sum', 'count']) | |
>>> cohorts.head() | |
sum count | |
first_order order_date | |
2014-01-03 2014-01-03 16.448 1 | |
2014-11-12 153.112 1 | |
2014-01-04 2014-01-04 288.060 1 | |
2014-01-05 2014-01-05 19.536 1 | |
2014-01-06 2014-01-06 4407.100 3 |
Последний шаг: посчитаем, сколько в среднем заказов и приносят клиенты в течение первого года. Для этого сначала просуммируем показатели каждой когорты, а затем усредним значения методом mean()
:
>>> cohorts.groupby('first_order').sum().mean() | |
sum 1949.850803 | |
count 3.988789 |
Готово! В среднем за первый год когорты делают по 4 заказа и приносят по $1949 долларов.
Есть много способов улучшить решение, например сгруппировать дневные когорты в недельные или месячные, визуализировать отчет в таблице или на графике. Наконец, интересно разбить когорты по каким-то признакам, например, отделить частных покупателей от компаний — наверняка их показатели существенно отличаются.
Обо всем этом в следующих сериях. Подписывайтесь на канал, чтобы не пропустить.
Адиос!