Как стать автором
Обновить

Как обсчитать RFM-анализ за 5 шагов

Уровень сложностиПростой
Время на прочтение5 мин
Количество просмотров316

RFM-анализ - это метод сегментации клиентов, основанный на их покупательской активности. С помощью RFM-анализа можно, во-первых, оценить доли клиентов в каждом из сегментов. Во-вторых, вспоминая постулат, что клиента легче удержать, чем привлечь. К пользователям, попавшими в разные сегменты, можно применять различные стратегии удержания / поощрения.

Сегментировать клиентов вообще можно различными способами. Как следует из названия, в RFM анализе сегментация идет по трем измерениям:

  • Recency (давность) — как давно клиент покупал

  • Frequency (частота) — как часто он покупает

  • Monetary (деньги) — какую сумму тратит

В каждом измерении выделяют обычно три ранга. Условно это градации "Хорошо", "Нормально", "Плохо". Ранги обычно кодируются как 1, 2, 3. Причем, как-то нет общепринятой договоренности, что кодирует "Хорошо" - 1 или 3. Поэтому лучше приводить расшифровку, как именно вы закодировали ранги.

Итого получается три измерения по три ранга или 27 сочетаний (сегментов) пользователей: от постоянно тратящих большие суммы, причем последний раз вот совсем недавно, до сделавших давным-давно один мааааленький платеж.

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

Общий алгоритм обсчета

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

2 Вычислить дополнительные показатели.

3 Определить границы рангов и присвоить их пользователям.

4 Построить RFM-таблицу, сгруппировав данные по рангам.

5 На основе полученной RFM-таблицы построить хитмап по определенному показателю

Обсчет RFM-анализа на примере Python

Допустим у нас есть датасет транзакций платежей пользователей за некоторый период. Минимальный набор данных для RFM-анализа: id транзакций, дата транзакции, id пользователя и сумма транзакции.

id

date

user_id

donate

332345

2023-01-01

406173

1000.00

332331

2023-01-01

350353

300.00

332333

2023-01-01

419745

500.00

332337

2023-01-01

343691

300.00

332339

2023-01-01

343285

1000.00

Шаг 1. Формируем таблицу клиентов

Далаем groupby по пользователям c агрегациями: количество транзакций, общая сумма транзакций, первая и последняя дата операций:

user_table = tranz.groupby('user_id').agg({
                  'id' : 'count', 
                  'donate' : 'sum'},
                  'date' : ['min', 'max']) 
user_table.columns = ('tr_count', 'donate_sum', 'first_date', 'last_date')

user_id

tr_count

donate_sum

first_date

last_date

343905

4

5280.00

2023-07-28

2024-10-23

343915

5

1500.00

2024-03-15

2024-11-06

343919

4

204000.00

2023-10-17

2024-06-11

343923

2

3200.00

2023-05-16

2023-05-16

343941

2

8710.00

2023-03-09

2023-12-29

Шаг 2. Вычисляем дополнительные показатели

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

  user_table['day_on'] = user_table['last_date'] - user_table['first_date']
  user_table['day_on'] = user_table['day_on'].dt.days + 1
  user_table['oper_frec'] = user_table['tr_count'] / user_table['month_on']

user_id

tr_count

donate_sum

first_date

last_date

day_on

oper_frec

343905

4

5280.00

2023-07-28

2024-10-23

454

0.25

343915

5

1500.00

2024-03-15

2024-11-06

237

0.62

343919

4

204000.00

2023-10-17

2024-06-11

239

0.50

343923

2

3200.00

2023-05-16

2023-05-16

1

2.00

343941

2

8710.00

2023-03-09

2023-12-29

296

0.20

Шаг 3. Определение границ рангов

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

В Python такое деление можно сделать с помощью функций pd.cut или pd.qcut

labels = ['1', '2', '3']
user_table['R1'] = pd.cut(user_table['day_last'], bins=[-1, 31, 90, 1000], labels=labels)
user_table['F1'] = pd.cut(user_table['oper_frec'], bins=[-1, 0.9, 2, 1000], labels=labels)
user_table['M1'] = pd.qcut(user_table['oper_sum'], q=[0, .33, .66, 1.], labels=labels)

Также можно использовать конструкции с lambda x или lambda row. В этом случае можно задавать условия деление на когорты с учетом значений в других колонках. Например, ниже "разовые" клиенты определены по одному дню жизни, пусть даже они сделали 10 платежей в этот день.

user_table_rfm['R'] = user_table_rfm['day_last']\
      .apply(lambda x: '1' if x < 45 else ('2' if x < 180 else '3'))
user_table_rfm['F'] = user_table_rfm\
      .apply(lambda row: '3' if row['day_on'] == 1 else ('2' if row['oper_frec'] < 0.8 else '1'), axis=1)
user_table_rfm['M'] = user_table_rfm['donate_sum']\
      .apply(lambda x: '1' if x > 2000 else ('2' if x > 750 else '3'))

user_id

tr_count

donate_sum

first_date

last_date

day_on

oper_frec

R

F

M

343905

4

5280.00

2023-07-28

2024-10-23

454

0.25

2

2

1

343915

5

1500.00

2024-03-15

2024-11-06

237

0.62

2

2

2

343919

4

204000.00

2023-10-17

2024-06-11

239

0.50

3

2

1

343923

2

3200.00

2023-05-16

2023-05-16

1

2.00

3

1

1

343941

2

8710.00

2023-03-09

2023-12-29

296

0.20

3

2

1

Шаг 4. Строим RFM таблицу

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

rfm_table = user_table_rfm.groupby(['R', 'F', 'M'], as_index = False)\
    .agg({'tr_count' : ['count', 'sum'], 
          'donate_sum' : 'sum'})
rfm_table.columns = ['R', 'F', 'M', 'RFM', 'rfm_users', 'rfm_tr', 'rfm_sum']

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

R

F

M

rfm_users

rfm_tr

rfm_sum

1

1

1

368

7694

8860328.26

1

1

2

20

158

27231.00

1

1

3

16

70

5944.00

1

2

1

152

1112

2814391.00

1

2

2

43

182

64151.00

Шаг 5. Выводим RFM таблицу в виде heatmap

Для вывода красивой RFM таблицы в виде тепловой карты надо еще провернуть один "фокус": так как таблица плоская, а измерений у нас три, то надо комбинацию двух измерений разместить на одной оси, а третье измерение на другой оси. Например, R И F по вертикали, а M горизонтали. Делается это через сводную таблицу pivot. В итоге должна получится матрица 9*3, в которой в индексах ранги R И F, в колонках ранги M, а в ячейках значения нужного показателя - количество пользователей, количество транзакций или сумма платежей. Эту сводную таблицу уже и выводим в виде heatmap.

fig = plt.figure(figsize = (12, 6))
rfm_pivot = rfm_table.pivot(index = ['R', 'F'], columns = 'M', values = 'rfm_sum').fillna(0)
sns.heatmap(rfm_pivot, cmap='RdYlGn', annot=True, cbar=False, fmt=',.0f')
plt.title(f'Тепловая карта RFM анализа по параметру Сумма платежей')
plt.show()

В итоге получится такая тепловая карта. Останется чуть-чуть поколдовать с метками осей, чтобы на хитмапе сразу было видно, что ранг 1 - это "Хорошо".

Заключение

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

Теги:
Хабы:
+1
Комментарии0

Публикации

Истории

Работа

Data Scientist
46 вакансий

Ближайшие события

19 марта – 28 апреля
Экспедиция «Рэйдикс»
Нижний НовгородЕкатеринбургНовосибирскВладивостокИжевскКазаньТюменьУфаИркутскЧелябинскСамараХабаровскКрасноярскОмск
24 апреля
VK Go Meetup 2025
Санкт-ПетербургОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань
14 мая
LinkMeetup
Москва
5 июня
Конференция TechRec AI&HR 2025
МоскваОнлайн
20 – 22 июня
Летняя айти-тусовка Summer Merge
Ульяновская область