7.36K subscribers
1.72K photos
72 videos
1 file
1.28K links
Привет! Мы — образовательная платформа в сфере аналитики Simulative: simulative.ru

Создаём курсы-симуляторы, где обучаем не на «апельсинках», а на кейсах из реального бизнеса.

Наш уютный чат: @itresume_chat
Поддержка: @simulative_support
Download Telegram
🔥 Как «распаковать» массив в PostgreSQL?

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

На самом же деле все просто. В PostgreSQL есть множество функций, связанных с массивами. Начнем с unnest() - самой простой для понимания, на наш взгляд.

🟢 Функция unnest() позволяет "распаковать" массивы в строки. Это очень удобно, если нужно отобразить массивы в виде простой таблицы.

В более старых версиях PostgreSQL для этого приходилось использовать медленные и сложные методы, но с unnest() все стало гораздо проще.

Как использовать функцию unnest() в PostgreSQL?

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

Синтаксис: unnest(array)

🟡 Например, если есть массив с числами от 1 до 5, то можно применить функцию unnest() и получить каждое число в отдельной строке таблицы.

SELECT unnest (ARRAY[1,2,3,4,5]);

|   | unnest |
|---|--------|
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |

Теперь давайте посмотрим, как сработает функция, если передать ей текст, а не цифры.

SELECT unnest (ARRAY['яблоко', 'лимон', 'банан']);

|   | unnest  |
|---|---------|
| 1 | яблоко |
| 2 | лимон |
| 3 | банан |

Видим, что она работает одинаково как для строковых значений, так и для чисел.

А что насчет многомерных массивов?

SELECT unnest (array[array[1, 2], array[2, 3], array[4,5]]);

|   | unnest |
|---|--------|
| 1 | 1 |
| 2 | 2 |
| 3 | 2 |
| 4 | 3 |
| 5 | 4 |
| 6 | 5 |

А если с несколькими массивами разных типов данных? Запросто.

Мы просто будем использовать синтаксис unnest (array1, array2, array3…):

SELECT * FROM
unnest
(
array [1, 2, 3],
array ['HP', 'AMD', 'APPLE']
)
AS data(ID, Company);

| | id | company |
|---|----|---------|
| 1 | 1 | HP |
| 2 | 2 | AMD |
| 3 | 3 | APPLE |

А если они разных размеров?

SELECT * FROM
unnest
(
array [1, 2, 3],
array ['HP', 'AMD', 'APPLE', 'DELL']
)
AS data(ID, Company);

| | id | company |
|---|--------|---------|
| 1 | 1 | HP |
| 2 | 2 | AMD |
| 3 | 3 | APPLE |
| 4 | [NULL] | DELL |

Если массивы имеют разное число элементов, то функция автоматически дополнит их NULL - значениями до нужного размера.

🖋 А теперь попробуйте решить такую задачку:

> У вас есть таблица "books", где для каждой книги указаны ее ID и список авторов (хранится как массив). Используя функцию unnest(), найдите все книги, написанные авторами, чьи имена начинаются на букву "A".

Пишите ваши запросы в комментариях!

#sql
👍12🔥8
🔥 Вакансия: Data Scientist (нейронные сети)

Сегодня мы с крутой новостью - ищем Data Scientist по направлению AI к себе в команду.

🔹 Направление: детекция объектов/текстов на изображениях (object detection, OCR)

🔹 Формат: удаленка, проект, частичная занятость/фултайм, с возможностью дальнейшего роста в международном стартапе

🔹 Опыт: от 1 года, наличие проектов object detection/OCR в портфолио

Присылайте свои резюме на почту a.alexanyan@itresume.ru и напишите в письме - почему именно вы подходите для этой вакансии 🙂

Будем рады видеть вас в команде! 🤩
🔥8👍2
🔥 Степени свободы в статистике

Как-то мы делали пост о различиях расчета стандартного отклонения в NumPy и Pandas. И пообещали вам напомнить, а что же такое эти степени свободы, в которых вся соль. Сегодня об этом и поговорим.

Степени свободы в статистике - это количество независимых переменных, используемых при вычислении переменной.

Формула: Степени свободы = Количество независимых значений - Количество статистик

Пример. У нас есть 50 независимых значений, и мы хотим вычислить одну статистику - "среднее". Согласно формуле, степеней свободы будет 50 - 1 = 49.

🟢 Давайте представим, что вы проводите эксперимент, в котором измеряете рост 10 человек. Вы знаете среднее значение роста этих людей. Однако если бы вы измеряли рост еще большего количества людей, то среднее значение могло бы отличаться от результата, который вы получили изначально.

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

Возвращаемся к стандартному отклонению. Как его считать?

1. Вычислите среднее значение набора данных.
2. Вычтите среднее значение из каждого значения в наборе данных.
3. Возведите в квадрат разности, полученные на шаге 2.
4. Сложите квадраты разностей, найденных на шаге 3.
5. Разделите сумму, полученную на шаге 4, на N (если берем генеральную совокупность) , либо на (N - 1) (если берем выборку). На этом этапе мы получили дисперсию.
6. Извлеките квадратный корень из результата шага 5, чтобы получить стандартное отклонение.

🟡 Концептуально мы можем понять это следующим образом: если бы мы имели доступ ко всей генеральной совокупности, мы могли бы точно вычислить истинное значение стандартного отклонения. Но если мы используем выборку, то у нас есть только ограниченный объем информации, который может привести к искажениям (и порой значительным).

Таким образом, мы должны скорректировать выборочную дисперсию, чтобы учесть этот факт. И именно поправка N-1 в знаменателе, позволяет учитывать этот фактор.

🟠 Вернемся к эксперименту с ростом людей.

Допустим, 10 человек - это генеральная совокупность, значения - [150, 193, 173, 184, 168, 201, 178, 175, 180, 182].

Используя NumPy, посчитаем стандартное отклонение генеральной совокупности: 13.14. Возьмем условную «выборку» - пять последних элементов, и посчитаем теперь для них.

import numpy as np

a = [201, 178, 175, 180, 182]
np.std(a)

# 9.195

Вспомним, что NumPy считает стандартное отклонение для генеральной совокупности (в знаменателе N - без степеней свободы), а мы уже работаем с выборкой, и нам нужно добавить одну степень свободы (N-1). Посмотрим, приблизимся ли мы к изначальному результату.

import numpy as np

a = [201, 178, 175, 180, 182]
np.std(a, ddof=1)

# 10.28

Действительно, стало поточнее. Конечно, 10 элементов с трудом можно назвать генеральной совокупностью, а половину - выборкой. Но убедиться, что это работает, можно!

Итог: используя степени свободы, вы получите несмещенную оценку, и это обеспечит вам более точные результаты. Поэтому не забывайте, что в NumPy по умолчанию ddof=0, а в Pandas ddof=1.

🔵 В нашем Симуляторе «Аналитик данных» подробно разбираем библиотеки Python для анализа данных и показываем, как использовать их в рабочих задачах!

#analytics #pandas #numpy
🔥9👍52
🔥 Бесплатный live-курс по SQL для начинающих 🔥

Приветствую!

На связи Андрон, CEO Simulative & IT Resume.

Хочу пригласить вас на свой бесплатный live-курс по SQL для начинающих: "Сегментация базы пользователей", который пройдёт с 16 по 17 мая в 19:00 по мск. 💥

Этот live-курс подойдет Вам, если:

🔹 У вас совсем нет опыта в SQL;
🔹 Вы немного владеете базовым SQL, но нет системности;
🔹 Вы никогда не применяли SQL для решения бизнес-задач.

На live-курсе помимо лекций будут 2 блока домашних заданий, доступ к боевому кластеру и реальный бизнес-кейс, который вам предстоит решить самостоятельно.

КУРС АБСОЛЮТНО БЕСПЛАТНЫЙ! 😉

🔗 Чтобы не пропустить трансляцию и получить конспект, переходите по ссылке 👉 https://mnlp.cc/mini?domain=simulative&id=7.

До встречи! 🙂
🔥8👍3🤩2
💥 Напоминание о бесплатном live-курсе по SQL 💥

Приветствуем!

Возможно, вы пропустили наш прошлый пост, поэтому дублируем информацию еще раз 🙃

Приглашаем вас на бесплатный live-курс по SQL для начинающих: "Сегментация базы пользователей", который пройдёт с 16 по 17 мая в 19:00 по мск. 🔥

Что вас ждет на live-курсе:

🔸 2 живых обучающих лекции с разбором практических заданий;
🔸 2 блока домашних задания (15 заданий);
🔸 Самостоятельное решение бизнес-кейса с обратной связью от преподавателя;
🔸 Доступ к боевому кластеру;
🔸 Работа с профессиональными инструментами и программами.

🔗 Чтобы не пропустить трансляцию и получить конспект, переходите по ссылке 👉 https://mnlp.cc/mini?domain=simulative&id=7.

До встречи на live-курсе! 😉
🔥9👍2
⁉️ А есть ли разница между Concat / Сoncat_ws / ||

Как часто вас учат, что можно заменить функцию concat оператором ||? А что, если мы скажем, что это не совсем так? Мы вместе с нашими студентами курса разбирались в этом во время решения домашних задач.

✏️ В PostgreSQL оператор || - это бинарный оператор, который используется для конкатенации двух строковых значений. Он просто соединяет две строки вместе, не добавляя никаких разделителей или других символов между ними.

SELECT 'IT' || 'Resume';
-- ITResume

В то время как функции concat() и concat_ws() также используются для конкатенации, но предоставляют некоторые дополнительные возможности. Например, функция concat() позволяет объединять любое количество строковых аргументов, а concat_ws() еще и принимает первым аргументом разделитель.

SELECT concat('IT', ' ', 'Resume');
-- IT Resume

SELECT concat_ws('-', '2023', '05', '15');
-- 2023-05-15

И на этом можно было бы остановиться, ведь уже понятно их различие. Но мы были бы не мы, если бы на этом закончили.

А что с NULL значениями?

Вот и ловушка! При использовании оператора || в PostgreSQL, если один из аргументов NULL, результат будет также NULL. Например:

SELECT 'SQL' || NULL;
-- NULL

А вот функции, вполне справятся с NULL значениями:

SELECT concat(NULL, NULL);
-- ''

SELECT concat_ws(' ', 'IT', NULL, 'Resume');
-- IT Resume

Почему так?

Оператор || работает по стандарту SQL, когда любое выражение, в котором участвует NULL должно равняться NULL. Потому что NULL это неизвестность. Как 42 * NULL даст NULL.

А функции concat и concat_ws если какой-то из элементов NULL - проигнорируют его и соединят остальное, но если все NULL - вернут пустую строку.

❗️ Так что будьте осторожны и присоединяйтесь к Симулятору «Аналитик данных», чтобы оценить свои навыки на рабочих кейсах!

#sql
🔥15👍5
📢 [Ласт-колл] на бесплатный live-курс по SQL для начинающих

Это Андрон, основатель IT Resume & Simulative. Просто хочу напомнить, что сегодня в 19:00 по мск пройдет первый день бесплатного live-курса по SQL для начинающих: "Сегментация базы пользователей"

🔗 Чтобы не пропустить трансляцию и получить конспект, переходите по ссылке 👉 https://mnlp.cc/mini?domain=simulative&id=7.

До встречи на трансляции! 😉
🔥42👍1
🤨 Действительно ли параметр inplace в Pandas ускоряет операции?

Многие пользователи Pandas считают, что использование операций с параметром inplace=True ускорит работу с датафреймами. Согласны ли вы с этим? Всегда ли это работает?

🟢 Давайте это проверим

Inplace - это параметр методов Pandas, который позволяет изменять DataFrame без создания нового объекта. Звучит так, будто это должно работать быстрее, но есть некоторые нюансы:

- Inplace, вопреки тому, что следует из названия, часто не препятствует созданию копий. Это первый пункт против скорости подобного способа.
- SettingWithCopy - часто получаемое предупреждение - оно не влияет на выполнение кода. Однако же получается Pandas выполняет дополнительные проверки, чтобы убедиться, что датафрейм изменен корректно. Соответственно, второй пункт против скорости inplace.
- И последнее - inplace операции могут быть менее гибкими, так как не позволяют объединить несколько методов в одной строке.

Но это лишь предположения, давайте убедимся в них!

🔵 Мы провели небольшой анализ

Смотрите в карточке под постом как некоторые методы работают с inplace.

❗️Какие-то методы действительно работают быстрее, некоторые гораздо быстрее, но все-таки большинство - медленнее.

Поэтому, перед тем, как применять inplace, обязательно оцените время и потенциальную пользу в вашем конкретном случае и не потеряйте важные данные!

🧠 Если хотите все проверить самостоятельно - делимся ссылкой на коллаб.

#python #pandas
🔥5
🔥8👍3
🔥 Поговорим о булевых столбцах в PostgreSQL

🤔 Небольшая предыстория. Мы обсуждали со студентами Симулятора «‎Аналитик данных»‎, что если столбец имеет булевый тип данных и нужно его указать в WHERE? Как можно изменить следующий запрос:

SELECT col1, col2, col3 
FROM table
WHERE col2 = True;

Надеемся, вы тоже знаете, что достаточно написать WHERE column2 если ищем значения True или WHERE NOT column2 если ищем значения False.

И тема развилась до того, что нашелся частный пример: имеется таблица, а в ней булевый столбец со значениями True, False и NULL. И если с выбором отдельных строк с True, False или NULL в данном случае все понятно. Просто пишем:

is null -- для выбора только строк со значениями NULL
= False / NOT boolean_column -- для выбра строк с False
= True / boolean_column -- для выбора строк с True;

🟠 То, что делать, если нужно достать строки, со значениями и False, и NULL?

Случился настоящий блиц! Были варианты:

SELECT * FROM table WHERE boolean_column is False or NULL;

Не сработает, так как интерпретируется как (boolean_column is False) or (null). Он возвращает только строки, где boolean_column равна False, так как второе условие всегда ложно.

SELECT * FROM table WHERE boolean_column is NULL or False;

Не сработает по той же причине. Интерпретируется как (boolean_column is Null) or (False).

Каков же правильный ответ?

Один из способов - использовать UNION двух запросов, которые по отдельности 100% работают:

SELECT * FROM table 
WHERE boolean_column IS NULL
UNION
SELECT * FROM table
WHERE NOT boolean_column

Можно еще попробовать неординарное COALESCE:

SELECT * FROM table
WHERE NOT COALESCE(boolean_column, False)

Этот запрос заменит все значения NULL на False, а затем выберет все значения False.

Еще один абсолютно рабочий вариант:

SELECT * FROM table
WHERE boolean_column is NULL
OR NOT boolean_column

💡 А на самом деле можно просто посмотреть на это с другой стороны:

В PostgreSQL есть 3 состояния для булевого столбца: True, False и неизвестность (NULL). Поэтому нам пригодится только запрос для NOT TRUE:

SELECT * FROM table
WHERE boolean_column IS NOT True;

💥 Не бойтесь выходить за рамки стандартного мышления, ведь верных решений может быть сколько угодно!

#sql
🔥19👍32
🔥 Переменная цикла и области видимости

Не так давно у нас был пост о том, что переменную цикла нельзя изменить внутри for-loop. Давайте продолжим тему переменной цикла, но взглянем на нее под другим углом!

🤔 Посмотрите на блоки кода ниже и ответьте, что вы получите после выполнения?

a = 1
for a in range(6):
pass

print(a)

------------------------

a = 1
[... for a in range(6)]

print(a)

Итак, в первом случае получим 5, а во втором - 1. То есть цикл for обновил существующую переменную a, но генератор списка этого не сделал. Итак, вопрос:

Почему переменная цикла обрабатывается по-разному в for-loops и list cоmprehension?

🟢 В цикле for переменная цикла как бы «утекает» в окружающую область видимости. Другими словами, как только цикл завершится, вы все равно сможете получить доступ к переменной цикла. Убедимся:

for loop_var in range(6):
pass

print(loop_var)
# 5

Мы могли бы написать даже что-то такое:

b = 1
for a in range(6):
pass

print(a, b)
# 5 1

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

🟠 Но генераторы списков так не работают. Вместо этого переменная цикла всегда остается локальной для генератора списка. Она никогда не утекает «наружу».

[... for loop_var2 in range(6)]

print(loop_var2)
# NameError: name 'loop_var2' is not defined

Вот почему существующая переменная a, которая также использовалась внутри генератора списка, осталась неизменной. Генератор списка определил переменную цикла (a), локальную для его области видимости.

#python
🔥10👍4🤩2
🔥 JOIN по неравенству

Часто вы используете в своей практике JOIN по неравенству? Думаем, не очень. Обычно все сводится к простому JOIN по равенству, вроде такого: ON t1.column = t2.column, верно?

Не осуждаем, это привычный и понятный способ. Но, например, при подсчете промежуточного итога по столбцу если не использовать оконки, как раз нужно джойнить по неравенству. Например, просуммируем всю прибыль полученную до даты сделки:

SELECT s1.date, s1.revenue, 
SUM(s2.revenue) AS total
FROM sales s1
JOIN sales s2
ON s1.date >= s2.date
GROUP BY s1.revenue, s1.date
ORDER BY s1.date;

ON s1.date >= s2.date и есть - JOIN по неравенству.

Что еще можно использовать в таких JOINах? Все операторы сравнения: <, >, <=, >=, !=, и <> и оператор BETWEEN.

🟢 Давайте потренируемся!

У нас есть три таблицы в нашей воображаемой базе данных: houses, renters и deals. (См. в карточках 1-2 под постом)

Перечислим дома, которые мы можем предложить нашим арендаторам. Это должны быть дома (1) в предпочтительном районе, (2) в пределах их ценового диапазона, (3) с требуемым количеством спален и (4) не заняты (т.е. не указаны в нашей таблице сделок).

Вот такой запрос с JOIN по неравенству может решить нашу задачу: (См. в карточке 2)

🔵 Где нам еще может пригодится JOIN по неравенству?

Например, перечислим все дома из нашей базы данных вместе с датой соответствующей сделки (если она есть). Но берем даты только после 1 марта.

SELECT h.id, h.address, 
d.date
FROM houses h
LEFT JOIN deals d
ON h.id = d.house_id
WHERE d.date >= '2020-03-01';

(Результат запроса см. в карточке 3)

Мы получим только два дома, у которых есть даты сделки. А вот написав JOIN по неравенству, все сработает на отлично:

SELECT h.id, h.address, 
d.date
FROM houses h
LEFT JOIN deals d
ON h.id = d.house_id
AND d.date >= '2020-03-01';

(Результат запроса см. в карточке 4)

🔸 Такие JOINы могут быть очень полезными в разных сценариях, поделитесь с нами вашим опытом использования таких запросов. Часто ли вам приходится с ними сталкиваться?

#sql
🔥7👍51
🔥10👍4
💥 А вы знаете что такое RFM-анализ?

В работе аналитика часто встречается задача - провести RFM-анализ. Но иногда это задание вызывает трудности, поскольку студентам не так часто объясняют что такое RFM-анализ и с чем его едят, хотя это крайне полезный метод.

Давайте разберемся!

🔵 Что это такое?

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

RFM - расшифровка:

- Recency (давность): как давно клиент совершал заказы.
- Frequency (частота покупок): сколько раз клиент совершал заказы.
- Monetary (деньги): на какую сумму клиент совершал заказы.

RFM-анализ активно используется в маркетинге, чтобы лучше понять клиентов и определить, какие из них нуждаются в большей внимательности, каких можно привлечь новыми продуктами или услугами.

🟣 Как это работает?

Суть RFM-анализа в том, что мы разделяем всех клиентов на группы, опираясь на то, как давно они сделали последнюю покупку, как часто покупали и насколько большой была сумма их заказов.

По каждому из этих признаков мы выделяем по три равные группы. Затем присваиваем каждой группе числовое обозначение от 1 до 3.

По давности заказа (recency):

- 1 — давние клиенты;
- 2 — сравнительно недавние клиенты;
- 3 — свежие клиенты.

По частоте покупок (frequency):

- 1 — покупает очень редко (единичные заказы);
- 2 — покупает нечасто;
- 3 — постоянный покупатель.

По сумме покупок (monetary):

- 1 — маленькая сумма;
- 2 — средняя сумма;
- 3 — большая сумма.

Например, клиент «111» покупал давно, один раз и на маленькую сумму. И скорее всего, нам не стоит за него бороться.

Но при этом клиентов «131», «132», «133» обязательно нужно попытаться вернуть - это наши уходящие постоянные клиенты с разным чеком. Отправляем им реактивационные письма, запрашиваем обратную связь, предлагаем бонусы, программы лояльности.

🔝Или пользователь «333»: покупает часто, на большую сумму и последняя покупка была недавно. Это наши лучшие клиенты. Таким клиентам следует уделять особое внимание, например, предлагать им эксклюзивные продукты или услуги, бонусы и скидки.

🟡 Что с этим делать?

С каждой группой можно строить отдельные коммуникации: давать им разную рекламу и делать разные email-рассылки. Например, группе постоянных VIP-клиентов высылать специальные предложения, а пользователям, которые давно не покупали — мотивирующую скидку, и настроить на них таргетированную рекламу.

⚙️ Границы давности, частоты и суммы покупок вы определяете самостоятельно. То есть, для какого-то бизнеса 10 000 руб. - это много для 1 клиента, а для какого-то - почти ничего. Или частота покупок на сайте авиабилетов будет существенно отличаться от частоты покупок в магазине «у дома». Поэтому здесь можете проявить фантазию, отталкиваясь от вашего бизнеса.

💡 Главное - помнить основной принцип: лучших клиентов мы стараемся удержать, средних «довести» до лучших, а уходящих и почти потерянных — вернуть. Потому что вернуть клиента всегда легче, чем привлечь нового!

А в следующем посте разберем как провести RFM-анализ на практике, с использованием SQL!

Приходите в наш 👉 Симулятор "Аналитика данных" 👈, чтобы точно знать как вести себя в боевых задачах!

#analytics
👍17🔥62
💥 RFM-анализ с помощью SQL

Сегодня мы с вами вместе пройдем по шагам и сделаем RFM-анализ для магазина «у дома».

У нас есть таблица orders с данными о покупках за последние 90 дней (мы нагенерировали случайных клиентов и заказов).  (см. Карточку 1)

Приступим!

⚙️
Порой бывает полезно ограничить RFM-анализ конкретными временными рамками. Например, смотреть только последний год, или только последние 3 месяца. В таких случаях не забывайте добавить WHERE условие. В нашем же случае 3 месяца - как раз подходящий срок, чтобы проследить ушедших клиентов и частоту покупок. 

🔵 Итак, для вычисления Recency мы должны выяснить дату последнего заказа клиента. Для Frequency добавим простой count по столбцу order_id. А Monetary получим, взяв среднее по столбцу order_amount. (см. Карточку 2)

🤔 Теперь, когда мы имеем подготовленные данные - можем сформировать сегменты. Тут придется поразмыслить.

🟣 Какова адекватная давность покупок в магазине «у дома»? Достаточно часто людям приходится что-то приобрести, даже если они не закупаются в этом магазине на месяц. Но взять условные 7 дней, пожалуй, некорректно, так как люди могут уезжать в отпуск, на дачу и тд. При этом не превращаясь в «потерянных». Поэтому обозначим условные 30 дней - постоянные покупатели, до 60 - уходящие, и более 60, скорее всего потерянные клиенты (переехавшие, или выбравшие новый, открывшийся в районе магазин 🙂).

🟡 Что насчет Frequency? Тут свобода для фантазии. На наших данных мы определили более 5 покупок - частые, более 3 - средние, и до 3 покупок - редкие. Вероятно, если бы это были настоящие заказы, можно было бы взять окна побольше, поскольку 5 покупок в магазине у дома за 90 дней - не выглядят как максимально частый клиент 🙂.

🟢 И, наконец, Monetary - у нас все покупки до 10 000 рублей. Соответственно, разделим их примерно так: свыше 5 000 - высокий чек, выше 2 000 - средний, и все, что ниже - низкий. 

И теперь напишем следующий запрос: (см. Карточки 3-4)

💡 Уже прослеживается распределение. Большинство клиентов являются частыми покупателями. Покупатель 111 явно не из нашего района - случайная покупка. И в целом, получается у нас очень хороший магазин - много 333, много 322. Теперь с каждой группой можно настраивать различные коммуникации.

🔴 Важный момент: на нашем симуляторе есть большое практическое задание на проведение RFM-анализа. И мы видели варианты решения «в лоб» с использованием NTILE.

Что делает такое решение? NTILE просто разделяет данные на максимально возможно равные сегменты, не опираясь на данные в этих сегментах.

Например попробуем на наших данных разделить каждую группу на 3. (см. Карточки 5-6)

Выглядит будто бы лучше, у нас больше двоек и единиц, и будто бы получается честнее. НО! Если посмотреть подробнее, клиент, покупавший у нас 25 дней назад - отнесен к потерянным, при этом он был покупателем частым и с высоким чеком. Вполне вероятно, что это отнесение несколько ошибочно (он мог просто уехать в отпуск). Аналогично, клиентов с 5 покупками отнесли к наименее частым - не всегда это будет корректно.

В целом, такое решение тоже может работать, чтобы предварительно посмотреть сегментацию, но если вы хотите провести качественный RFM-анализ крайне важно адаптировать его под ваш бизнес.

#analytics #sql
🔥11👍64
🔥231👍1