У практичній частині ми продовжимо аналізувати наш сервіс та розрахуємо кілька важливих показників, що характеризують його роботу. Вам буде запропоновано написати кілька SQL-запитів та візуалізувати їх.
21.1 Задача 1
Для початку давайте проаналізуємо, наскільки швидко зростає аудиторія нашого сервісу та подивимося на динаміку числа користувачів та кур’єрів.
Завдання 21.1 Для кожного дня, представленого в таблицях user_actions та courier_actions, розрахуйте такі показники:
Число нових користувачів.
Число нових кур’єрів.
Загальна кількість користувачів на сьогодні.
Загальна кількість кур’єрів на цей день.
Колонки з показниками назвіть відповідно new_users, new_couriers, total_users, total_couriers. Колонку з датами назвіть date. Простежте, щоб показники були виражені цілими числами. Результат має бути відсортований за зростанням дати.
Поля в результуючій таблиці: date, new_users, new_couriers, total_users, total_couriers
Пояснення:
Новими вважатимемо тих користувачів та кур’єрів, які в цей день здійснили свою першу дію в нашому сервісі. Загальна кількість користувачів/кур’єрів на поточний день — це результат додавання числа нових користувачів/кур’єрів у поточний день зі значеннями аналогічного показника всіх попередніх днів.
Підказка на випадок, якщо зовсім не виходить
Щоб порахувати кількість нових користувачів/кур’єрів на кожну дату спочатку необхідно для кожного користувача/кур’єра визначити мінімальну дату, тобто дату першої дії в нашому сервісі. Потім потрібно провести групування і для кожної отриманої дати порахувати кількість користувачів/кур’єрів із цією датою. Далі до отриманої таблиці достатньо застосувати віконну функцію і кожної дати обчислити накопичувальну суму числа користувачів/кур’єрів.
Рішення
%%sqlSELECT start_date as date, new_users, new_couriers, (sum(new_users) OVER (ORDER BY start_date))::intas total_users, (sum(new_couriers) OVER (ORDER BY start_date))::intas total_couriersFROM (SELECT start_date, count(courier_id) as new_couriers FROM (SELECT courier_id,min(time::date) as start_date FROM courier_actions GROUP BY courier_id) t1 GROUP BY start_date) t2 LEFT JOIN (SELECT start_date, count(user_id) as new_users FROM (SELECT user_id,min(time::date) as start_date FROM user_actions GROUP BY user_id) t3 GROUP BY start_date) t4 using (start_date)
date
new_users
new_couriers
total_users
total_couriers
0
2022-08-24
134
95
134
95
1
2022-08-25
829
242
963
337
2
2022-08-26
1017
219
1980
556
3
2022-08-27
1225
186
3205
742
4
2022-08-28
1487
213
4692
955
5
2022-08-29
1309
109
6001
1064
6
2022-08-30
1204
127
7205
1191
7
2022-08-31
1420
195
8625
1386
8
2022-09-01
1513
205
10138
1591
9
2022-09-02
1887
229
12025
1820
10
2022-09-03
1924
161
13949
1981
11
2022-09-04
1952
205
15901
2186
12
2022-09-05
1397
120
17298
2306
13
2022-09-06
1020
98
18318
2404
14
2022-09-07
1412
220
19730
2624
15
2022-09-08
1671
202
21401
2826
Запишемо результат запиту у змінну results.
Код
%%sqlresults << SELECT start_date as date, new_users, new_couriers, (sum(new_users) OVER (ORDER BY start_date))::intas total_users, (sum(new_couriers) OVER (ORDER BY start_date))::intas total_couriersFROM (SELECT start_date, count(courier_id) as new_couriers FROM (SELECT courier_id,min(time::date) as start_date FROM courier_actions GROUP BY courier_id) t1 GROUP BY start_date) t2 LEFT JOIN (SELECT start_date, count(user_id) as new_users FROM (SELECT user_id,min(time::date) as start_date FROM user_actions GROUP BY user_id) t3 GROUP BY start_date) t4 using (start_date)
Проаналізуйте побудовані графіки та спробуйте відповісти на такі питання:
Що зростає швидше: кількість користувачів чи кількість кур’єрів?
Наскільки стабільні показники числа нових користувачів та кур’єрів? Чи немає даних таких днів, коли показники сильно вибивалися із загальної динаміки?
Чи можна сказати, що кількість нових кур’єрів більш стабільна, ніж кількість нових користувачів?
21.2 Задача 2
Аналізуючи динаміку показників із попереднього завдання, ви могли помітити, що порівнювати абсолютні значення не дуже зручно. Давайте порахуємо динаміку показників у відносних величинах.
Завдання 21.2 Доповніть запит із попереднього завдання і тепер для кожного дня, поданого в таблицях user_actions та courier_actions, додатково розрахуйте такі показники:
Приріст числа нових користувачів.
Приріст числа нових кур’єрів.
Приріст загальної кількості користувачів.
Приріст загальної кількості кур’єрів.
Показники, розраховані на попередньому кроці, також включіть у результуючу таблицю.
Колонки з новими показниками назвіть відповідно new_users_change, new_couriers_change, total_users_growth, total_couriers_growth. Колонку з датами назвіть date.
Усі показники приросту рахуйте у відсотках відносно попереднього дня. Під час розрахунку показників округляйте значення до двох знаків після коми.
Результуюча таблиця має бути відсортована за зростанням дати.
Поля в результуючій таблиці: date, new_users, new_couriers, total_users, total_couriers, new_users_change, new_couriers_change, total_users_growth, total_couriers_growth
Пояснення:
Не забувайте при діленні заздалегідь наводити значення до потрібного типу даних. Пропущені значення приростів для першої дати не заповнюйте - просто залиште поля в цьому рядку порожніми.
Підказка на випадок, якщо зовсім не виходить
Для розрахунку приростів скористайтесь віконними функціями та функціями зсунення.
Рішення
%%sqlSELECT date, new_users, new_couriers, total_users, total_couriers,round(100* (new_users - lag(new_users, 1) OVER (ORDER BY date)) / lag(new_users, 1) OVER (ORDER BY date)::decimal,2) as new_users_change,round(100* (new_couriers - lag(new_couriers, 1) OVER (ORDER BY date)) / lag(new_couriers, 1) OVER (ORDER BY date)::decimal,2) as new_couriers_change,round(100* new_users::decimal / lag(total_users, 1) OVER (ORDER BY date),2) as total_users_growth,round(100* new_couriers::decimal / lag(total_couriers, 1) OVER (ORDER BY date),2) as total_couriers_growthFROM (SELECT start_date as date, new_users, new_couriers, (sum(new_users) OVER (ORDER BY start_date))::intas total_users, (sum(new_couriers) OVER (ORDER BY start_date))::intas total_couriers FROM (SELECT start_date, count(courier_id) as new_couriers FROM (SELECT courier_id,min(time::date) as start_date FROM courier_actions GROUP BY courier_id) t1 GROUP BY start_date) t2 LEFT JOIN (SELECT start_date, count(user_id) as new_users FROM (SELECT user_id,min(time::date) as start_date FROM user_actions GROUP BY user_id) t3 GROUP BY start_date) t4 using (start_date)) t5
date
new_users
new_couriers
total_users
total_couriers
new_users_change
new_couriers_change
total_users_growth
total_couriers_growth
0
2022-08-24
134
95
134
95
NaN
NaN
NaN
NaN
1
2022-08-25
829
242
963
337
518.66
154.74
618.66
254.74
2
2022-08-26
1017
219
1980
556
22.68
-9.50
105.61
64.99
3
2022-08-27
1225
186
3205
742
20.45
-15.07
61.87
33.45
4
2022-08-28
1487
213
4692
955
21.39
14.52
46.40
28.71
5
2022-08-29
1309
109
6001
1064
-11.97
-48.83
27.90
11.41
6
2022-08-30
1204
127
7205
1191
-8.02
16.51
20.06
11.94
7
2022-08-31
1420
195
8625
1386
17.94
53.54
19.71
16.37
8
2022-09-01
1513
205
10138
1591
6.55
5.13
17.54
14.79
9
2022-09-02
1887
229
12025
1820
24.72
11.71
18.61
14.39
10
2022-09-03
1924
161
13949
1981
1.96
-29.69
16.00
8.85
11
2022-09-04
1952
205
15901
2186
1.46
27.33
13.99
10.35
12
2022-09-05
1397
120
17298
2306
-28.43
-41.46
8.79
5.49
13
2022-09-06
1020
98
18318
2404
-26.99
-18.33
5.90
4.25
14
2022-09-07
1412
220
19730
2624
38.43
124.49
7.71
9.15
15
2022-09-08
1671
202
21401
2826
18.34
-8.18
8.47
7.70
Запишемо результат запиту у змінну results.
Код
%%sqlresults << SELECT date, new_users, new_couriers, total_users, total_couriers,round(100* (new_users - lag(new_users, 1) OVER (ORDER BY date)) / lag(new_users, 1) OVER (ORDER BY date)::decimal,2) as new_users_change,round(100* (new_couriers - lag(new_couriers, 1) OVER (ORDER BY date)) / lag(new_couriers, 1) OVER (ORDER BY date)::decimal,2) as new_couriers_change,round(100* new_users::decimal / lag(total_users, 1) OVER (ORDER BY date),2) as total_users_growth,round(100* new_couriers::decimal / lag(total_couriers, 1) OVER (ORDER BY date),2) as total_couriers_growthFROM (SELECT start_date as date, new_users, new_couriers, (sum(new_users) OVER (ORDER BY start_date))::intas total_users, (sum(new_couriers) OVER (ORDER BY start_date))::intas total_couriers FROM (SELECT start_date, count(courier_id) as new_couriers FROM (SELECT courier_id,min(time::date) as start_date FROM courier_actions GROUP BY courier_id) t1 GROUP BY start_date) t2 LEFT JOIN (SELECT start_date, count(user_id) as new_users FROM (SELECT user_id,min(time::date) as start_date FROM user_actions GROUP BY user_id) t3 GROUP BY start_date) t4 using (start_date)) t5
(a) Динаміка приросту числа нових користувачів та кур’єрів
(b) Динаміка приросту загальної кількості користувачів та кур’єрів
Рисунок 21.2: Графік за результатами SQL-запиту
Проаналізуйте побудовані графіки та спробуйте відповісти на такі питання:
Як змінилися темпи приросту загальної кількості користувачів і кур’єрів за проміжок часу, що розглядається? Яка загалом динаміка цих показників: вони ростуть чи, навпаки, згасають?
У які дні темп приросту числа нових кур’єрів помітно випереджав темп приросту нових користувачів?
Чи можна, дивлячись на графіки з відносними показниками, сказати, що кількість нових кур’єрів більш стабільний, ніж показник числа нових користувачів?
21.3 Задача 3
Тепер пропонуємо вам подивитися на нашу аудиторію трохи під іншим кутом - давайте порахуємо не просто всіх користувачів, а саме ту частину, яка оформлює та оплачує замовлення у нашому сервісі. Заодно з’ясуємо, яку частку користувачі, що платять, становлять від їх загального числа.
Завдання 21.3 Для кожного дня, представленого в таблицях user_actions та courier_actions, розрахуйте такі показники:
Число користувачів, які оплачують замовлення.
Число активних кур’єрів.
Частку користувачів, що платять, в загальній кількості користувачів на поточний день.
Частку активних кур’єрів у кількості кур’єрів на поточний день.
Колонки з показниками назвіть відповідно paying_users, active_couriers, paying_users_share, active_couriers_share. Колонку з датами назвіть date. Простежте, щоб абсолютні показники були виражені цілими числами. Усі показники часток необхідно виразити у відсотках. Під час їх розрахунку округляйте значення до двох знаків після коми.
Результат має бути відсортований за зростанням дати.
Поля в результуючій таблиці: date, paying_users, active_couriers, paying_users_share, active_couriers_share
Пояснення:
Користувачів, які оплачують замовлення будемо вважати тих, які в даний день оформили хоча б одне замовлення, яке надалі не було скасовано.
Кур’єрів вважатимемо активними, якщо в даний день вони прийняли хоча б одне замовлення, яке було доставлено (можливо вже наступного дня), або доставили будь-яке замовлення.
Загальна кількість користувачів/кур’єрів на поточний день – це, як і раніше, результат складання числа нових користувачів/кур’єрів у поточний день зі значеннями аналогічного показника всіх попередніх днів. Ми рахували цей показник на попередніх кроках.
Не забувайте при діленні заздалегідь наводити значення до потрібного типу даних.
Підказка на випадок, якщо зовсім не виходить
Для вирішення завдання необхідно спочатку для кожного дня порахувати кількість користувачів, які оплачують замовлення, і активних кур’єрів, а потім об’єднати отримані таблиці з даними про загальну кількість користувачів і кур’єрів на поточну дату і далі розрахувати всі необхідні відносні показники. Загальну кількість користувачів та кур’єрів на поточну дату ми вже рахували раніше.
Рішення
%%sqlSELECT date, paying_users, active_couriers,round(100* paying_users::decimal / total_users, 2) as paying_users_share,round(100* active_couriers::decimal / total_couriers, 2) as active_couriers_shareFROM (SELECT start_date as date, new_users, new_couriers, (sum(new_users) OVER (ORDER BY start_date))::intas total_users, (sum(new_couriers) OVER (ORDER BY start_date))::intas total_couriers FROM (SELECT start_date, count(courier_id) as new_couriers FROM (SELECT courier_id,min(time::date) as start_date FROM courier_actions GROUP BY courier_id) t1 GROUP BY start_date) t2 LEFT JOIN (SELECT start_date, count(user_id) as new_users FROM (SELECT user_id,min(time::date) as start_date FROM user_actions GROUP BY user_id) t3 GROUP BY start_date) t4 using (start_date)) t5 LEFT JOIN (SELECT time::date as date, count(distinct courier_id) as active_couriers FROM courier_actions WHERE order_id notin (SELECT order_id FROM user_actions WHERE action ='cancel_order') GROUP BY date) t6 using (date) LEFT JOIN (SELECT time::date as date, count(distinct user_id) as paying_users FROM user_actions WHERE order_id notin (SELECT order_id FROM user_actions WHERE action ='cancel_order') GROUP BY date) t7 using (date)
date
paying_users
active_couriers
paying_users_share
active_couriers_share
0
2022-08-24
127
93
94.78
97.89
1
2022-08-25
820
333
85.15
98.81
2
2022-08-26
1137
526
57.42
94.60
3
2022-08-27
1548
721
48.30
97.17
4
2022-08-28
2083
927
44.39
97.07
5
2022-08-29
2202
1022
36.69
96.05
6
2022-08-30
2253
1133
31.27
95.13
7
2022-08-31
2430
1286
28.17
92.78
8
2022-09-01
2710
1474
26.73
92.65
9
2022-09-02
3429
1733
28.52
95.22
10
2022-09-03
3794
1906
27.20
96.21
11
2022-09-04
4104
2069
25.81
94.65
12
2022-09-05
3362
2047
19.44
88.77
13
2022-09-06
2701
1883
14.75
78.33
14
2022-09-07
3517
2245
17.83
85.56
15
2022-09-08
3912
2491
18.28
88.15
Запишемо результат запиту у змінну results.
Код
%%sqlresults << SELECT date, paying_users, active_couriers,round(100* paying_users::decimal / total_users, 2) as paying_users_share,round(100* active_couriers::decimal / total_couriers, 2) as active_couriers_shareFROM (SELECT start_date as date, new_users, new_couriers, (sum(new_users) OVER (ORDER BY start_date))::intas total_users, (sum(new_couriers) OVER (ORDER BY start_date))::intas total_couriers FROM (SELECT start_date, count(courier_id) as new_couriers FROM (SELECT courier_id,min(time::date) as start_date FROM courier_actions GROUP BY courier_id) t1 GROUP BY start_date) t2 LEFT JOIN (SELECT start_date, count(user_id) as new_users FROM (SELECT user_id,min(time::date) as start_date FROM user_actions GROUP BY user_id) t3 GROUP BY start_date) t4 using (start_date)) t5 LEFT JOIN (SELECT time::date as date, count(distinct courier_id) as active_couriers FROM courier_actions WHERE order_id notin (SELECT order_id FROM user_actions WHERE action ='cancel_order') GROUP BY date) t6 using (date) LEFT JOIN (SELECT time::date as date, count(distinct user_id) as paying_users FROM user_actions WHERE order_id notin (SELECT order_id FROM user_actions WHERE action ='cancel_order') GROUP BY date) t7 using (date)
(a) Динаміка користувачів, які платять та активних кур’єрів:
(b) Динаміка часток користувачів, які платять та активних кур’єрів:
Рисунок 21.3: Графік за результатами SQL-запиту
Проаналізуйте побудовані графіки та спробуйте відповісти на такі питання:
Чи можна сказати, що разом із загальною кількістю користувачів і кур’єрів зростає кількість користувачів, що платять, і активних кур’єрів?
Як водночас поводяться показники часток користувачів, що платять, і активних кур’єрів? Чи можна вважати їхню поточну динаміку в цілому нормальною та закономірною?
21.4 Задача 4
Давайте докладніше зупинимося на користувачах, які оплачують замовлення, копнем трохи глибше і з’ясуємо, як багато користувачів, які оплачують замовленняь, здійснюють більше одного замовлення в день. Зрештою нам важливо розуміти, як здебільшого поводяться наші користувачі — вони заходять у додаток, щоб зробити всього одне замовлення, або наш сервіс настільки хороший, що вони готові користуватися ним кілька разів на день.
Завдання 21.4 Для кожного дня, поданого в таблиці user_actions, розрахуйте такі показники:
Частку користувачів, які зробили в цей день всього одне замовлення, від загальної кількості користувачів, які оплачують замовлення.
Частку користувачів, які зробили цього дня кілька замовлень, від загальної кількості користувачів, які оплачують замовлення.
Назвіть колонки з показниками відповідно single_order_users_share, several_orders_users_share. Колонку з датами назвіть date. Усі показники із частками необхідно виразити у відсотках. При розрахунку часток округляйте значення до двох знаків після коми.
Результат має бути відсортований за зростанням дати.
Поля в результуючій таблиці: date, single_order_users_share, several_orders_users_share
Пояснення:
Користувачами, що оплачують замовлення, як і раніше, вважаємо тих користувачів, які в даний день оформили (і не скасували) хоча б одне замовлення.
Не забувайте при діленні заздалегідь наводити значення до потрібного типу даних.
Підказка на випадок, якщо зовсім не виходить
Для вирішення завдання спочатку необхідно для кожного дня окремо розрахувати загальну кількість користувачів, що оплачують замовлення, кількість користувачів з одним замовленням і кількість користувачів з кількома замовленнями. Потім необхідно поєднати таблиці з цими даними за датою та порахувати всі необхідні показники.
Рішення
%%sqlSELECT day::date AS date, ROUND(100* COUNT(DISTINCT user_id) FILTER(WHERE count_orders =1) / COUNT(DISTINCT user_id)::numeric, 2) AS single_order_users_share, ROUND(100* COUNT(DISTINCT user_id) FILTER(WHERE count_orders !=1) / COUNT(DISTINCT user_id)::numeric, 2) AS several_orders_users_shareFROM(SELECT user_id, COUNT(DISTINCT order_id) AS count_orders, DATE_TRUNC('day', time) AS dayFROM user_actionsWHERE order_id NOT IN (SELECT order_id FROM user_actions WHERE action ='cancel_order')GROUP BY user_id, day) AS t1GROUP BY dayORDER BY day
date
single_order_users_share
several_orders_users_share
0
2022-08-24
92.91
7.09
1
2022-08-25
76.46
23.54
2
2022-08-26
78.45
21.55
3
2022-08-27
70.93
29.07
4
2022-08-28
67.83
32.17
5
2022-08-29
65.58
34.42
6
2022-08-30
64.67
35.33
7
2022-08-31
70.41
29.59
8
2022-09-01
71.70
28.30
9
2022-09-02
67.02
32.98
10
2022-09-03
63.94
36.06
11
2022-09-04
65.94
34.06
12
2022-09-05
69.96
30.04
13
2022-09-06
77.67
22.33
14
2022-09-07
72.65
27.35
15
2022-09-08
69.61
30.39
Запишемо результат запиту у змінну results:
Код
%%sqlresults << SELECT day::date AS date, ROUND(100* COUNT(DISTINCT user_id) FILTER(WHERE count_orders =1) / COUNT(DISTINCT user_id)::numeric, 2) AS single_order_users_share, ROUND(100* COUNT(DISTINCT user_id) FILTER(WHERE count_orders !=1) / COUNT(DISTINCT user_id)::numeric, 2) AS several_orders_users_shareFROM(SELECT user_id, COUNT(DISTINCT order_id) AS count_orders, DATE_TRUNC('day', time) AS dayFROM user_actionsWHERE order_id NOT IN (SELECT order_id FROM user_actions WHERE action ='cancel_order')GROUP BY user_id, day) AS t1GROUP BY dayORDER BY day
Рисунок 21.4: Частки користувачів з одним та кількома замовленнями
Проаналізуйте побудовані графіки та спробуйте відповісти на такі питання:
На якому рівні у середньому тримається частка користувачів із кількома замовленнями?
Чи можна вважати значення показника в перший день аномально низьким, якщо взяти до уваги загальну кількість користувачів цього дня?
21.5 Задача 5
Продовжимо вивчати наш сервіс та розрахуємо декілька показників, пов’язаних із замовленнями.
Завдання 21.5 Для кожного дня, поданого в таблиці user_actions, розрахуйте такі показники:
Загальна кількість замовлень.
Число перших замовлень (замовлень, зроблених користувачами вперше).
Число замовлень нових користувачів (замовлень, зроблених користувачами того ж дня, коли вони вперше скористалися сервісом).
Частку перших замовлень у кількості замовлень (частку п.2 в п.1).
Частку замовлень нових користувачів у кількості замовлень (частку п.3 в п.1).
Назвіть колонки з показниками відповідно orders, first_orders, new_users_orders, first_orders_share, new_users_orders_share. Колонку з датами назвіть date. Простежте, щоб у всіх випадках кількість замовлень була виражена цілим числом. Усі показники із частками необхідно виразити у відсотках. При розрахунку часток округляйте значення до двох знаків після коми.
Результат має бути відсортований за зростанням дати.
Поля в результуючій таблиці: date, orders, first_orders, new_users_orders, first_orders_share, new_users_orders_share
Пояснення:
При розрахунку числа перших замовлень враховуйте, що у кожного користувача може бути лише одне перше замовлення (що цілком логічно).
При розрахунку числа замовлень нових користувачів враховуйте, що у свій перший день кожен новий користувач міг як зробити відразу кілька замовлень, так і не здійснити жодного.
У всіх випадках при розрахунку числа замовлень враховуйте лише фактично здійснені замовлення, скасовані замовлення не враховуйте.
Не забувайте при діленні заздалегідь приводити значення до потрібного типу даних.
Підказка на випадок, якщо зовсім не виходить
Для вирішення завдання спочатку необхідно для кожного дня окремо розрахувати загальну кількість замовлень, кількість перших замовлень і кількість замовлень нових користувачів, а потім об’єднати отримані таблиці в одну і порахувати всі відносні показники. Для розрахунку числа перших замовлень для кожного користувача потрібно знайти дату оформлення першого нескасованого замовлення і потім здійснити групування за датою, порахувавши для кожного дня кількість користувачів, які зробили перше замовлення. Для розрахунку числа замовлень нових користувачів спочатку потрібно для кожного користувача знайти дату здійснення першої дії, а потім доповнити цю таблицю даними про кількість замовлень, зроблених користувачем свого першого дня. Це можна зробити, приєднавши до таблиці з датами перших дій таблицю із загальною кількістю замовлень на кожну дату для кожного користувача. Зверніть увагу, що в цій таблиці для деяких користувачів можуть бути відсутні дати здійснення першої дії оскільки користувач міг скасувати замовлення і фактично не здійснити жодної покупки свого першого дня. Після об’єднання таблиць для таких днів із пропущеними значеннями слід вказати кількість замовлень рівним 0. Це можна зробити, наприклад, за допомогою функції COALESCE.
Рішення
%%sqlSELECT date, orders, first_orders, new_users_orders::intas new_users_orders, ROUND(100* first_orders::decimal / orders, 2) AS first_orders_share, ROUND(100* new_users_orders::decimal / orders, 2) AS new_users_orders_share FROM ( SELECT creation_time::date AS date, COUNT(DISTINCT order_id) AS orders FROM orders WHERE order_id NOT IN (SELECT order_id FROM user_actions WHERE action='cancel_order') AND order_id IN (SELECT order_id FROM courier_actions WHERE action='deliver_order') GROUP BY date ) t5 LEFT JOIN ( SELECT first_order_date AS date, COUNT(user_id) AS first_orders FROM ( SELECT user_id, MIN(time::date) AS first_order_date FROM user_actions WHERE order_id NOT IN (SELECT order_id FROM user_actions WHERE action='cancel_order') GROUP BY user_id ) t4 GROUP BY first_order_date ) t7 USING (date) LEFT JOIN ( SELECT start_date AS date, SUM(orders) AS new_users_orders FROM ( SELECT t1.user_id, t1.start_date, COALESCE(t2.orders, 0) AS orders FROM ( SELECT user_id, MIN(time::date) AS start_date FROM user_actions GROUP BY user_id ) t1 LEFT JOIN ( SELECT user_id, time::date AS date, COUNT(DISTINCT order_id) AS orders FROM user_actions WHERE order_id NOT IN (SELECT order_id FROM user_actions WHERE action='cancel_order') GROUP BY user_id, date ) t2 ON t1.user_id = t2.user_id AND t1.start_date = t2.date ) t3 GROUP BY start_date ) t6 USING (date) ORDER BY date
date
orders
first_orders
new_users_orders
first_orders_share
new_users_orders_share
0
2022-08-24
138
127
138
92.03
100.00
1
2022-08-25
1059
802
1032
75.73
97.45
2
2022-08-26
1447
984
1250
68.00
86.39
3
2022-08-27
2141
1192
1624
55.67
75.85
4
2022-08-28
2998
1460
2102
48.70
70.11
5
2022-08-29
3267
1281
1832
39.21
56.08
6
2022-08-30
3371
1180
1714
35.00
50.85
7
2022-08-31
3410
1380
1908
40.47
55.95
8
2022-09-01
3688
1492
1988
40.46
53.90
9
2022-09-02
5001
1864
2655
37.27
53.09
10
2022-09-03
5709
1907
2830
33.40
49.57
11
2022-09-04
6010
1943
2763
32.33
45.97
12
2022-09-05
4675
1387
1865
29.67
39.89
13
2022-09-06
3451
1012
1264
29.32
36.63
14
2022-09-07
4777
1416
1865
29.64
39.04
15
2022-09-08
5474
1661
2300
30.34
42.02
Запишемо результат запиту у змінну results:
Код
%%sqlresults << SELECT date, orders, first_orders, new_users_orders::intas new_users_orders, ROUND(100* first_orders::decimal / orders, 2) AS first_orders_share, ROUND(100* new_users_orders::decimal / orders, 2) AS new_users_orders_share FROM ( SELECT creation_time::date AS date, COUNT(DISTINCT order_id) AS orders FROM orders WHERE order_id NOT IN (SELECT order_id FROM user_actions WHERE action='cancel_order') AND order_id IN (SELECT order_id FROM courier_actions WHERE action='deliver_order') GROUP BY date ) t5 LEFT JOIN ( SELECT first_order_date AS date, COUNT(user_id) AS first_orders FROM ( SELECT user_id, MIN(time::date) AS first_order_date FROM user_actions WHERE order_id NOT IN (SELECT order_id FROM user_actions WHERE action='cancel_order') GROUP BY user_id ) t4 GROUP BY first_order_date ) t7 USING (date) LEFT JOIN ( SELECT start_date AS date, SUM(orders) AS new_users_orders FROM ( SELECT t1.user_id, t1.start_date, COALESCE(t2.orders, 0) AS orders FROM ( SELECT user_id, MIN(time::date) AS start_date FROM user_actions GROUP BY user_id ) t1 LEFT JOIN ( SELECT user_id, time::date AS date, COUNT(DISTINCT order_id) AS orders FROM user_actions WHERE order_id NOT IN (SELECT order_id FROM user_actions WHERE action='cancel_order') GROUP BY user_id, date ) t2 ON t1.user_id = t2.user_id AND t1.start_date = t2.date ) t3 GROUP BY start_date ) t6 USING (date) ORDER BY date
(a) Динаміка загальної кількості замовлень, числа перших замовлень та числа замовлень нових користувачів
(b) Динаміка частки перших замовлень та частки замовлень нових користувачів у кількості замовлень
Рисунок 21.5: Графік за результатами SQL-запиту
Проаналізуйте побудовані графіки та спробуйте відповісти на такі питання:
Яка загалом динаміка у абсолютних показників? Чи можна сказати, що разом із зростанням кількості всіх замовлень зростають показники числа перших замовлень та кількості замовлень нових користувачів?
Що можна сказати про динаміку відносних показників? Чи можна вважати її загалом закономірною? Як, на ваш погляд, поводитимуться ці показники у довгостроковій перспективі: вони зростатимуть чи знижуватимуться?
21.6 Задача 6
Тепер давайте спробуємо приблизно оцінити навантаження на наших кур’єрів і дізнаємося, скільки в середньому замовлень та користувачів припадає на кожного з них.
Завдання 21.6 На основі даних у таблицях user_actions, courier_actions та orders для кожного дня розрахуйте такі показники:
Кількість користувачів, що оплатили замовлення на одного активного кур’єра.
Кількість замовлень на одного активного кур’єра.
Колонки з показниками назвіть відповідно users_per_courier та orders_per_courier. Колонку з датами назвіть date. Під час розрахунку показників округляйте значення до двох знаків після коми.
Результуюча таблиця має бути відсортована за зростанням дати.
Поля в результуючій таблиці: date, users_per_courier, orders_per_courier
Пояснення:
Користувачів, що оплатили замовлення, як і раніше, вважаємо тих користувачів, які в даний день оформили хоча б одне замовлення, яке надалі не було скасовано.
Кур’єрів вважаємо активними, якщо в даний день вони прийняли хоча б одне замовлення, яке було доставлено (можливо вже наступного дня), або доставили будь-яке замовлення.
У розрахунках враховуйте лише нескасовані замовлення.
Не забувайте при діленні заздалегідь наводити значення до потрібного типу даних.
Підказка на випадок, якщо зовсім не виходить
Для вирішення завдання спочатку необхідно за допомогою групування та агрегації розрахувати кількість користувачів, кур’єрів та замовлень на кожну дату, а потім об’єднати дані в одну таблицю та провести всі необхідні розрахунки.
Рішення
%%sqlSELECT date,round(paying_users::decimal / couriers, 2) as users_per_courier,round(orders::decimal / couriers, 2) as orders_per_courierFROM (SELECT time::date as date, count(distinct courier_id) as couriers FROM courier_actions WHERE order_id notin (SELECT order_id FROM user_actions WHERE action ='cancel_order') GROUP BY date) t1 join (SELECT creation_time::date as date, count(distinct order_id) as orders FROM orders WHERE order_id notin (SELECT order_id FROM user_actions WHERE action ='cancel_order') GROUP BY date) t2 using (date) join (SELECT time::date as date, count(distinct user_id) as paying_users FROM user_actions WHERE order_id notin (SELECT order_id FROM user_actions WHERE action ='cancel_order') GROUP BY date) t3 using (date)ORDER BY date
date
users_per_courier
orders_per_courier
0
2022-08-24
1.37
1.48
1
2022-08-25
2.46
3.18
2
2022-08-26
2.16
2.75
3
2022-08-27
2.15
2.97
4
2022-08-28
2.25
3.23
5
2022-08-29
2.15
3.20
6
2022-08-30
1.99
2.98
7
2022-08-31
1.89
2.65
8
2022-09-01
1.84
2.50
9
2022-09-02
1.98
2.89
10
2022-09-03
1.99
3.00
11
2022-09-04
1.98
2.90
12
2022-09-05
1.64
2.28
13
2022-09-06
1.43
1.83
14
2022-09-07
1.57
2.13
15
2022-09-08
1.57
2.20
Запишемо результат запиту у змінну results:
Код
%%sqlresults << SELECT date,round(paying_users::decimal / couriers, 2) as users_per_courier,round(orders::decimal / couriers, 2) as orders_per_courierFROM (SELECT time::date as date, count(distinct courier_id) as couriers FROM courier_actions WHERE order_id notin (SELECT order_id FROM user_actions WHERE action ='cancel_order') GROUP BY date) t1 join (SELECT creation_time::date as date, count(distinct order_id) as orders FROM orders WHERE order_id notin (SELECT order_id FROM user_actions WHERE action ='cancel_order') GROUP BY date) t2 using (date) join (SELECT time::date as date, count(distinct user_id) as paying_users FROM user_actions WHERE order_id notin (SELECT order_id FROM user_actions WHERE action ='cancel_order') GROUP BY date) t3 using (date)ORDER BY date
Рисунок 21.6: Динаміка числа користувачів та замовлень на одного кур’єра
Проаналізуйте побудовані графіки та спробуйте відповісти на такі питання:
Чи збігається загалом динаміка аналізованих показників? Якщо так, то чому так відбувається?
Як змінюються показники? Вони швидше зростають чи, навпаки, падають? Про що може говорити така динаміка?
Як ви вважаєте, чи високе навантаження у кур’єрів нашого сервісу? Чи варто сервісу продовжувати збільшувати кількість кур’єрів чи, навпаки, зараз краще призупинити нарощування їх чисельності?
21.7 Задача 7
Розрахуємо ще один корисний показник, що характеризує якість роботи кур’єрів.
Завдання 21.7 На основі даних у таблиці courier_actions для кожного дня розрахуйте, за скільки хвилин у середньому кур’єри доставляли свої замовлення.
Назвіть колонку з показником minutes_to_deliver. Колонку з датами назвіть date. При розрахунку середнього часу доставки округляйте кількість хвилин до цілих значень. Враховуйте лише доставлені замовлення, скасовані замовлення не враховуйте.
Результуюча таблиця має бути відсортована за зростанням дати.
Поля в результуючій таблиці: date, minutes_to_deliver
Пояснення:
Для вирішення завдання вам, можливо, доведеться згадати, як визначити кількість хвилин, що містяться в інтервалі часу. Ми вже вирішували схожу задачу у завданні 20.7.
Деякі замовлення оформляють одного дня, а доставляють вже наступного. При розрахунку середнього часу доставки в якості днів, для яких рахується середнє, використовуйте дні фактичної доставки замовлень.
Підказка на випадок, якщо зовсім не виходить
Для вирішення завдання спочатку необхідно за допомогою групування та агрегації для кожного замовлення розрахувати час прийняття замовлення кур’єром (мінімальна позначка часу) та час доставки (максимальна позначка часу), обчислити різницю між цими значеннями та за допомогою функції EXTRACT витягти з неї секунди (epoch), перевівши їх за хвилини. Потім можна провести групування за датою доставки та обчислити середній час доставки у кожний із днів.
Рішення
%%sqlSELECT date,round(avg(delivery_time))::intas minutes_to_deliverFROM (SELECT order_id,max(time::date) as date, extract(epoch FROM max(time) -min(time))/60as delivery_time FROM courier_actions WHERE order_id notin (SELECT order_id FROM user_actions WHERE action ='cancel_order') GROUP BY order_id) tGROUP BY dateORDER BY date
date
minutes_to_deliver
0
2022-08-24
20
1
2022-08-25
20
2
2022-08-26
20
3
2022-08-27
20
4
2022-08-28
20
5
2022-08-29
20
6
2022-08-30
20
7
2022-08-31
20
8
2022-09-01
20
9
2022-09-02
20
10
2022-09-03
20
11
2022-09-04
20
12
2022-09-05
20
13
2022-09-06
20
14
2022-09-07
20
15
2022-09-08
20
Запишемо результат запиту у змінну results:
Код
%%sqlresults << SELECT date,round(avg(delivery_time))::intas minutes_to_deliverFROM (SELECT order_id,max(time::date) as date, extract(epoch FROM max(time) -min(time))/60as delivery_time FROM courier_actions WHERE order_id notin (SELECT order_id FROM user_actions WHERE action ='cancel_order') GROUP BY order_id) tGROUP BY dateORDER BY date
Рисунок 21.7: Динаміка середнього часу доставки замовлень
Проаналізуйте побудований графік та спробуйте відповісти на наступні питання:
Який, найімовірніше, час очікування доставки замовлення в нашому сервісі?
Чи вдається кур’єрам дотримуватися цього цільового показника?
21.8 Задача 8
І нарешті, давайте оцінимо погодинне навантаження на наш сервіс, з’ясуємо, в які години користувачі оформлюють найбільше замовлень, і заразом проаналізуємо, як змінюється частка скасування залежно від часу оформлення замовлення.
Завдання 21.8 На основі даних у таблиці orders для кожної години на добу розрахуйте такі показники:
Число успішних (доставлених) замовлень.
Число скасованих замовлень.
Частку скасованих замовлень у загальній кількості замовлень (cancel rate).
Колонки з показниками назвіть відповідно successful_orders, canceled_orders, cancel_rate. Колонку із годиною оформлення замовлення назвіть hour. При розрахунку частки скасованих замовлень округляйте значення до трьох знаків після коми.
Результуюча таблиця має бути відсортована за зростанням колонки з годиною оформлення замовлення.
Поля в результуючій таблиці: hour, successful_orders, canceled_orders, cancel_rate
Підказка на випадок, якщо зовсім не виходить
Для вирішення завдання можна спочатку за допомогою групування за датою та агрегацією окремо розрахувати кількість успішних та скасованих замовлень, потім об’єднати дві таблиці в одну за датою і потім розрахувати cancel rate.
Рішення
%%sqlSELECT hour, successful_orders, canceled_orders,round(canceled_orders::decimal / (successful_orders + canceled_orders),3) as cancel_rateFROM (SELECT date_part('hour', creation_time)::intas hour, count(order_id) as successful_orders FROM orders WHERE order_id notin (SELECT order_id FROM user_actions WHERE action ='cancel_order') GROUP BY hour) t1 LEFT JOIN (SELECT date_part('hour', creation_time)::intas hour, count(order_id) as canceled_orders FROM orders WHERE order_id in (SELECT order_id FROM user_actions WHERE action ='cancel_order') GROUP BY hour) t2 using (hour)ORDER BY hour
hour
successful_orders
canceled_orders
cancel_rate
0
0
2297
139
0.057
1
1
1867
98
0.050
2
2
1422
62
0.042
3
3
958
56
0.055
4
4
926
48
0.049
5
5
1363
77
0.053
6
6
1583
101
0.060
7
7
2101
100
0.045
8
8
2195
117
0.051
9
9
2606
151
0.055
10
10
2641
135
0.049
11
11
2584
121
0.045
12
12
2440
124
0.048
13
13
2424
122
0.048
14
14
2351
120
0.049
15
15
2513
128
0.048
16
16
2480
158
0.060
17
17
2966
168
0.054
18
18
3149
162
0.049
19
19
3496
189
0.051
20
20
3414
163
0.046
21
21
3197
172
0.051
22
22
2978
127
0.041
23
23
2665
141
0.050
Запишемо результат запиту у змінну results:
Код
%%sqlresults << SELECT hour, successful_orders, canceled_orders,round(canceled_orders::decimal / (successful_orders + canceled_orders),3) as cancel_rateFROM (SELECT date_part('hour', creation_time)::intas hour, count(order_id) as successful_orders FROM orders WHERE order_id notin (SELECT order_id FROM user_actions WHERE action ='cancel_order') GROUP BY hour) t1 LEFT JOIN (SELECT date_part('hour', creation_time)::intas hour, count(order_id) as canceled_orders FROM orders WHERE order_id in (SELECT order_id FROM user_actions WHERE action ='cancel_order') GROUP BY hour) t2 using (hour)ORDER BY hour
Рисунок 21.8: Динаміка показника cancel rate та числа успішних/скасованих замовлень:
Проаналізуйте побудований графік та спробуйте відповісти на такі питання:
В які години спостерігаються пікові значення числа замовлень? В які години користувачі здійснюють найменше замовлень?
Чи простежується якийсь взаємозв’язок між кількістю оформлених замовлень і часткою скасованих замовлень? Чи зростає зі збільшенням числа замовлень показник cancel rate?
21.9 Побудова дашборду
Здається, ми порахували вже багато різних показників і збудували достатньо графіків, щоб зібрати з них повноцінний дашборд!
Побудова дашбордів — творче завдання, тому ми не нічим вас обмежуватимемо. Можете вигадати свої візуалізації, додати графіки з лекції і навіть порахувати свої метрики. Головне — не забувайте про те, що дашборди мають бути зрозумілими та зручними для користувачів.
(a) New Users and Couriers by Date
(b) Total Users and Couriers Growth
(c) New Users and Couriers Change by Date, %
(d) Total Users and Couriers Change by Date, %
(e) Paying Users and Active Couriers
(f) Orders, First Orders and Orders of New Users by Date
(g) Paying Users and Active Couriers Share, %
(h) First Orders and Orders of New Users Share, %
(i) Single Order Users and Several Orders Users Share, %
(j) Orders by Hour
(k) Users and Orders per Courier
(l) Average Delivery Time by Date
Рисунок 21.9: Приклад дашборду з результатами SQL-запитів