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 анализа.
ссылка на оригинал статьи https://habr.com/ru/articles/900172/
Добавить комментарий