Описание проекта
Получение данных из базы данных сервиса Всё.из.кафе для использования их в исследовании точек роста сервиса и построения для этого дашбордов в Tableau.
Описание данных
Используемые таблицы из БД проекта:
module3_analytics_events
— таблица журнала (лог) аналитических событий. Сюда попадают данные о посещении пользователем страниц продукта и покупках;module3_cities
— таблица-справочник населённых пунктов, в которых можно пользоваться продуктом;module3_partners
— таблица-справочник партнёрских сетей и их ресторанов.
Таблица module3_analytics_events
:
visitor_uuid
— идентификатор посетителя. Он присваивается системой любому новому пользователю вне зависимости от того, зарегистрировался он в продукте или нет;user_id
— идентификатор зарегистрированного пользователя. Присваивается посетителю после создания учётной записи: ввода логина, пароля, адреса доставки и контактных данных;device_type
— тип платформы, с которой посетитель зашёл в продукт;city_id
— город, из которого посетитель зашёл в сервис;age
— возрастная группа пользователя (указывается при регистрации);source
— рекламный источник привлечения посетителя;first_date
— дата первого посещения продукта;visit_id
— уникальный идентификатор сессии;event
— название аналитического события;datetime
— дата и время события;log_date
— дата события;rest_id
— уникальный идентификатор ресторана (заполняется для заказов, карточек ресторанов и блюд);object_id
— уникальный идентификатор блюда (заполняется для заказов и карточек блюд);listing_id
— уникальный идентификатор блюда в листинге. Листинг — набор блюд, которые рекомендуются системой пользователю при просмотре страницы ресторана. Заполняется только для событий типа rest_page;.position
— позиция блюда в листинге. Чем меньше номер, тем ближе блюдо к началу страницы. Заполняется только для событий типа rest_page;order_id
— уникальный идентификатор заказа;revenue
— выручка от заказа, в рублях. Это та сумма, которую пользователь видит при оплате;delivery
— стоимость доставки, в рублях;commission
— комиссия, которую «Всё.из.кафе» берёт с выручки ресторана, в процентахvisit_num
— порядковый номер сессии пользователя;order_num
— порядковый номер покупки, совершённой пользователем.
Таблица module3_cities
:
city_id
— уникальный идентификатор населённого пункта;city_name
— название населённого пункта.
Таблица module3_partners
:
rest_id
— уникальный идентификатор ресторана;chain
— название сети, к которой принадлежит ресторан;type
— тип кухни;city_id
— город, в котором находится ресторан;commission
— комиссия, которую «Всё.из.кафе» берёт с выручки ресторана, в процентах.
1. Распределение числа пользовательских сессий ¶
Получение максимального числа сессий для каждого из пользователей, установивших продукт в период с 2021-06-15
по 2021-07-01
. Построение распределения максимального числа сессий с разбивкой по типам устройств. В исследование user journey
попадают и зарегистрированные, и незарегистрированные пользователи, то есть анализ проводится по visitor_uuid
.
Перед изучением user journey полезно уточнить объём данных, участвующих в исследовании. Например, если пользователи не заходят в продукт более трёх раз, то путь стоит изучать только в рамках первых трёх сессий.
-- Профили пользователей
WITH profiles as (
SELECT DISTINCT visitor_uuid,
FIRST_VALUE(city_name) OVER (PARTITION BY visitor_uuid ORDER BY datetime) AS city_name,
FIRST_VALUE(first_date) OVER (PARTITION BY visitor_uuid ORDER BY datetime) AS first_date,
FIRST_VALUE(device_type) OVER (PARTITION BY visitor_uuid ORDER BY datetime) AS device_type,
FIRST_VALUE(source) OVER (PARTITION BY visitor_uuid ORDER BY datetime) AS source
FROM module3_analytics_events AS a
LEFT JOIN module3_cities c ON a.city_id = c.city_id
WHERE first_date BETWEEN '2021-06-15' AND '2021-07-01'
AND visit_num = 1
),
-- Максимальное число сессий на пользователя
sessions AS (
SELECT visitor_uuid,
MAX(visit_num) AS sessions_num
FROM module3_analytics_events
WHERE first_date BETWEEN '2021-06-15' AND '2021-07-01'
AND log_date BETWEEN '2021-06-15' AND '2021-07-01'
GROUP BY visitor_uuid
)
-- Профили пользователей и их сессии
SELECT p.device_type,
s.sessions_num,
COUNT(DISTINCT s.visitor_uuid) AS uniques
FROM sessions s
LEFT JOIN profiles p ON s.visitor_uuid = p.visitor_uuid
GROUP BY p.device_type,
s.sessions_num
ORDER BY p.device_type,
s.sessions_num;
device_type | sessions_num | uniques |
---|---|---|
Desktop | 1 | 6240 |
Desktop | 2 | 718 |
Desktop | 3 | 171 |
Desktop | 4 | 63 |
Desktop | 5 | 19 |
Desktop | 6 | 2 |
Deskto | 8 | 5 |
Desktop | 9 | 1 |
Desktop | 13 | 1 |
Mobil | 1 | 4948 |
Mobile | 2 | 349 |
Mobile | 3 | 54 |
Mobile | 4 | 17 |
Mobile | 5 | 4 |
Mobile | 6 | 1 |
Mobile | 9 | 1 |
2. Распределение первых покупок по номерам сессий ¶
Рассчеи для каждого покупателя номера сессии, в которой была совершена первая покупка. Рассчет медианного номера сессии с разбивкой по платформам. Кроме общего числа сессий, стоит уточнить, в рамках какой сессии чаще всего наступает целевое событие — первая покупка.
-- Профили пользователей
WITH profiles as (
SELECT DISTINCT visitor_uuid,
FIRST_VALUE(c.city_name) OVER (PARTITION BY visitor_uuid ORDER BY datetime) AS city_name,
FIRST_VALUE(a.first_date) OVER (PARTITION BY visitor_uuid ORDER BY datetime) AS first_date,
FIRST_VALUE(a.device_type) OVER (PARTITION BY visitor_uuid ORDER BY datetime) AS device_type,
FIRST_VALUE(a.source) OVER (PARTITION BY visitor_uuid ORDER BY datetime) AS source
FROM module3_analytics_events AS a
LEFT JOIN module3_cities c ON a.city_id = c.city_id
WHERE first_date BETWEEN '2021-06-15' AND '2021-07-01'
AND visit_num = 1
),
-- Покупки и их номера
orders AS (
SELECT visitor_uuid,
visit_num,
DENSE_RANK() OVER (PARTITION BY visitor_uuid ORDER BY datetime) AS event_num
FROM module3_analytics_events
WHERE first_date BETWEEN '2021-06-15' AND '2021-07-01'
AND log_date BETWEEN '2021-06-15' AND '2021-07-01'
AND event = 'order'
)
-- Расчёт медиан
SELECT p.device_type,
COUNT (DISTINCT o.visitor_uuid) AS buyers,
PERCENTILE_CONT(.5) WITHIN GROUP (ORDER BY o.visit_num) AS median_visit_num
FROM orders o
LEFT JOIN profiles p ON o.visitor_uuid = p.visitor_uuid
WHERE o.event_num = 1
GROUP BY p.device_type
ORDER BY buyers DESC;
device_type | buyers | median_visit_num |
---|---|---|
Desktop | 458 | 1 |
Mobile | 226 | 1 |
3. Изучение последовательности действий пользователей ¶
Анализ последовательности действий, совершаемых пользователем в рамках первой сессии. Результат выполнения запроса содержит:
- Наименование аналитического события.
- Номер аналитического события в цепочке событий, совершённых каждым из пользователей.
- Число пользователей, совершивших событие. Например, если у 100 пользователей первым было событие authorization, вторым — main_page, а третьим — order, то должна получиться таблица:
authorization | 1 | 100 |
---|---|---|
main_page | 2 | 100 |
order | 3 | 100 |
К результату добавлена разбивка по городам, датам и источникам привлечения пользователей, а также по типам устройств. Для каждого пользователя получены первые 10 событий.
-- Профили пользователей
WITH profiles as (
SELECT DISTINCT visitor_uuid,
FIRST_VALUE(c.city_name) OVER (PARTITION BY visitor_uuid ORDER BY datetime) AS city_name,
FIRST_VALUE(a.first_date) OVER (PARTITION BY visitor_uuid ORDER BY datetime) AS first_date,
FIRST_VALUE(a.device_type) OVER (PARTITION BY visitor_uuid ORDER BY datetime) AS device_type,
FIRST_VALUE(a.source) OVER (PARTITION BY visitor_uuid ORDER BY datetime) AS source
FROM module3_analytics_events AS a
LEFT JOIN module3_cities c ON a.city_id = c.city_id
WHERE first_date BETWEEN '2021-06-15' AND '2021-07-01'
AND visit_num = 1
),
-- События, совершённые пользователями за первую сессию, и их номера
events AS (
SELECT visitor_uuid,
visit_num,
event,
DENSE_RANK() OVER (PARTITION BY visitor_uuid ORDER BY datetime) AS event_num
FROM module3_analytics_events
WHERE first_date BETWEEN '2021-06-15' AND '2021-07-01'
AND log_date BETWEEN '2021-06-15' AND '2021-07-01'
AND visit_num = 1
),
-- События и профили вместе
events_profiles AS (
SELECT e.visitor_uuid,
p.city_name,
p.first_date,
p.device_type,
p.source,
visit_num,
event,
event_num
FROM events e
LEFT JOIN profiles p ON e.visitor_uuid = p.visitor_uuid
)
-- Финальные вычисления
SELECT city_name,
first_date,
device_type,
source,
visit_num,
event_num,
event,
COUNT(visitor_uuid) AS events
FROM events_profiles
WHERE event_num <= 10
GROUP BY city_name,
first_date,
device_type,
source,
visit_num,
event_num,
event;
city_name | first_date | device_type | source | visit_num | event_num | event | events |
---|---|---|---|---|---|---|---|
Новосибирск | 2021-06-25 | Mobile | Source_B | 1 | 6 | main_page | 22 |
Новосибирск | 2021-06-24 | Mobile | organic | 1 | 6 | login | 1 |
Новосибирск | 2021-06-24 | Desktop | Source_B | 1 | 7 | confirm_phone | 1 |
Мурино | 2021-06-21 | Desktop | organic | 1 | 3 | main_page | 24 |
Саранск | 2021-06-27 | Desktop | Source_B | 1 | 8 | rest_page | 3 |
Владивосток | 2021-06-19 | Desktop | Source_C | 1 | 1 | reg_page | 1 |
Саранск | 2021-07-01 | Mobile | organic | 1 | 4 | reg_page | 1 |
Владивосток | 2021-06-18 | Mobile | Source_B | 1 | 2 | main_page | 1 |
Сочи | 2021-06-23 | Mobile | organic | 1 | 7 | object_page | 1 |
… | … | … | … | … | … | … | … |
4. User journey ¶
Запрос для формирования user journey
и его визуализации в Tableau. Запрос возвращает:
- Идентификатор пользователя.
- Наименование аналитического события.
- Минимальный лайфтайм в минутах от момента первого входа в продукт до наступления аналитического события.
Для каждого пользователя добавлен город, дата и источник привлечения, а также тип устройства.
-- Профили пользователей
WITH profiles as (
SELECT DISTINCT visitor_uuid,
FIRST_VALUE(c.city_name) OVER (PARTITION BY visitor_uuid ORDER BY datetime) AS city_name,
FIRST_VALUE(a.datetime) OVER (PARTITION BY visitor_uuid ORDER BY datetime) AS first_datetime,
FIRST_VALUE(a.first_date) OVER (PARTITION BY visitor_uuid ORDER BY datetime) AS first_date,
FIRST_VALUE(a.device_type) OVER (PARTITION BY visitor_uuid ORDER BY datetime) AS device_type,
FIRST_VALUE(a.source) OVER (PARTITION BY visitor_uuid ORDER BY datetime) AS source
FROM module3_analytics_events AS a
LEFT JOIN module3_cities c ON a.city_id = c.city_id
WHERE first_date BETWEEN '2021-06-15' AND '2021-07-01'
AND visit_num = 1
),
-- События, совершённые пользователями за первую сессию
events AS (
SELECT visitor_uuid,
event,
datetime
FROM module3_analytics_events
WHERE first_date BETWEEN '2021-06-15' AND '2021-07-01'
AND log_date BETWEEN '2021-06-15' AND '2021-07-01'
AND visit_num = 1
)
-- Профили, события и время их наступления
SELECT e.visitor_uuid,
p.city_name,
p.first_date,
p.device_type,
p.source,
e.event,
EXTRACT(epoch FROM MIN(e.datetime - p.first_datetime)) / 60 AS time_to_event
FROM events e
LEFT JOIN profiles p ON e.visitor_uuid = p.visitor_uuid
GROUP BY e.visitor_uuid,
p.city_name,
p.first_date,
p.device_type,
p.source,
e.event;
visitor_uuid | city_name | first_date | device_type | source | event | time_to_event |
---|---|---|---|---|---|---|
00015d39-ace9-4976-b3d6-e647b4aee83f | Новосибирск | 2021-06-23 | Mobile | organic | authorization | 0 |
00015d39-ace9-4976-b3d6-e647b4aee83f | Новосибирск | 2021-06-23 | Mobile | organic | main_page | 1.93333 |
00015d39-ace9-4976-b3d6-e647b4aee83f | Новосибирск | 2021-06-23 | Mobile | organic | reg_page | 1.88333 |
0001ad5a-84b9-442b-a518-d1ea8d7a1cf0 | Саранск | 2021-06-17 | Desktop | organic | authorization | 0 |
0001ad5a-84b9-442b-a518-d1ea8d7a1cf0 | Саранск | 2021-06-17 | Desktop | organic | main_page | 0.25 |
0008137e-4841-4b94-9116-0f976e6f6142 | Мурино | 2021-06-18 | Desktop | organic | authorization | 0 |
0008137e-4841-4b94-9116-0f976e6f6142 | Мурино | 2021-06-18 | Desktop | organic | main_page | 0.0833333 |
… | … | … | … | … | … | … |
5. RFM-анализ ¶
Подготовка данных для проведения RFM-анализа платящих пользователей в Tableau. Для каждого покупателя определены RFM-сегменты, город, дата и источник привлечения, а также тип устройства. Для исследования RFM-сегментации используется интервал регистрации пользователей с 2021-05-01
по 2021-06-01
.
-- Профили пользователей
WITH profiles as (
SELECT DISTINCT user_id,
FIRST_VALUE(c.city_name) OVER (PARTITION BY user_id ORDER BY datetime) AS city_name,
FIRST_VALUE(a.first_date) OVER (PARTITION BY user_id ORDER BY datetime) AS first_date,
FIRST_VALUE(a.device_type) OVER (PARTITION BY user_id ORDER BY datetime) AS device_type,
FIRST_VALUE(a.source) OVER (PARTITION BY user_id ORDER BY datetime) AS source
FROM module3_analytics_events AS a
LEFT JOIN module3_cities c ON a.city_id = c.city_id
WHERE first_date BETWEEN '2021-05-01' AND '2021-06-01'
AND user_id IS NOT NULL
),
-- Покупки пользователей
orders AS (
SELECT 'dummy' AS dummy_key,
user_id,
MIN(DATE('2021-07-01') - log_date) AS recency,
COUNT(log_date) AS frequency,
SUM(revenue) AS monetary_value
FROM module3_analytics_events
WHERE first_date BETWEEN '2021-05-01' AND '2021-06-01'
and event = 'order'
GROUP BY user_id
),
-- Границы RFM-групп
boundaries AS (
SELECT 'dummy' AS dummy_key,
PERCENTILE_CONT(.33) WITHIN GROUP(ORDER BY recency) AS p33_recency,
PERCENTILE_CONT(.66) WITHIN GROUP(ORDER BY recency) AS p66_recency,
PERCENTILE_CONT(.33) WITHIN GROUP(ORDER BY frequency) AS p33_frequency,
PERCENTILE_CONT(.66) WITHIN GROUP(ORDER BY frequency) AS p66_frequency,
PERCENTILE_CONT(.33) WITHIN GROUP(ORDER BY monetary_value) AS p33_monetary_value,
PERCENTILE_CONT(.66) WITHIN GROUP(ORDER BY monetary_value) AS p66_monetary_value
FROM orders
),
-- Определение RFM-групп для пользователей
rfm AS (
SELECT user_id,
recency,
frequency,
monetary_value,
p33_recency,
p66_recency,
p33_frequency,
p66_frequency,
p33_monetary_value,
p66_monetary_value,
CASE
WHEN recency <= p33_recency THEN 3
WHEN recency <= p66_recency AND recency > p33_recency THEN 2
ELSE 1
END AS r,
CASE
WHEN frequency <= p33_frequency THEN 1
WHEN frequency <= p66_frequency AND frequency > p33_frequency THEN 2
ELSE 3
END AS f,
CASE
WHEN monetary_value <= p33_monetary_value THEN 1
WHEN monetary_value <= p66_monetary_value AND monetary_value > p33_monetary_value THEN 2
ELSE 3
END AS m
FROM orders o
LEFT JOIN boundaries b ON b.dummy_key = o.dummy_key
)
-- Объединение RFM-групп с профилями
SELECT r.user_id,
city_name,
first_date,
device_type,
source,
r, f, m
FROM rfm r
LEFT JOIN profiles p ON p.user_id = r.user_id;
user_id | city_name | first_date | device_type | source | r | f | m |
---|---|---|---|---|---|---|---|
5210 | Сочи | 2021-05-05 | Desktop | Source_C | 1 | 1 | 2 |
5506 | Сочи | 2021-05-04 | Desktop | Source_C | 3 | 2 | 2 |
6291 | Сочи | 2021-05-06 | Desktop | organic | 1 | 1 | 1 |
6820 | Сочи | 2021-05-22 | Mobile | Source_C | 2 | 1 | 1 |
11062 | Саранск | 2021-05-06 | Desktop | organic | 1 | 1 | 2 |
13254 | Саранск | 2021-05-09 | Mobile | Source_B | 1 | 1 | 1 |
13319 | Саранск | 2021-05-06 | Desktop | Source_C | 1 | 1 | 3 |
14394 | Саранск | 2021-05-08 | Mobile | Source_B | 1 | 1 | 1 |
… | … | … | … | … | … | … | … |
6. ABC-XYZ-анализ ¶
Подготовка данных для проведения ABC-XYZ-анализа партнёрских сетей ресторанов в Tableau. Для каждой сети определены ABC- и XYZ-сегменты.
-- Рассчитываем недельную выручку сетей
WITH daily_revenue AS (
SELECT p.chain,
date_trunc('week', log_date) as log_week,
SUM(revenue) AS revenue
FROM module3_analytics_events e
LEFT JOIN module3_partners p on p.rest_id = e.rest_id
WHERE event = 'order'
GROUP BY p.chain,
date_trunc('week', log_date)
),
-- Рассчитываем коэффициенты вариативности
partners AS (
SELECT chain,
SUM(revenue) AS revenue,
STDDEV(revenue) AS std,
STDDEV(revenue) / AVG(revenue) AS var_coeff
FROM daily_revenue
GROUP BY chain
),
-- Рассчитываем доли от общей выручки
abc_xyz AS (
SELECT chain,
revenue,
SUM(revenue) OVER (ORDER BY revenue DESC) AS cumulative_revenue,
SUM(revenue) OVER () tot_rev,
SUM(revenue) OVER (ORDER BY revenue DESC) / SUM(revenue) OVER () AS perc,
std,
var_coeff
FROM partners
ORDER BY revenue DESC
)
-- Распределяем партнёрские рестораны по группам
SELECT chain,
CASE
WHEN perc <= .8 THEN 'A'
WHEN perc <= .95 THEN 'B'
ELSE 'C'
END AS abc,
CASE
WHEN var_coeff <= .1 THEN 'X'
WHEN var_coeff <= .3 THEN 'Y'
ELSE 'Z'
END AS xyz
FROM abc_xyz;
chain | abc | xyz |
---|---|---|
Гурманское Наслаждение | A | Z |
Гастрономический Шторм | A | Z |
Шоколадный Рай | A | Z |
Завтраки на любой вкус | A | Z |
Завтрак на полную | B | Z |
Утренний прием | B | Z |
Салатный Лес | B | Z |
Здоровый Шанс | B | Z |
Ресторан Добрых Выборов | B | Z |
Бутербродный Путешественник | C | Z |
Завтраки на каждый день | C | Z |
Венецианский Паб | C | Z |
Мамма Миа | C | Z |
Бутербродная Вселенная | C | Z |
Сладкий Путь | C | Z |
Кондитерская История | C | Z |
Сэндвичный Парад | C | Z |
Флорентийский Ресторан | C | Z |
Невероятные Бутерброды | C | Z |
Паста и Приятели | C | Z |