Все материалы
Продуктовая аналитикаматериалсредний

RFM-анализ: что это, как посчитать в SQL и что делать с сегментами

RFM-анализ делит клиентов по давности, частоте и сумме покупок. Как посчитать баллы в SQL, назвать сегменты и что делать, если бизнес работает по подписке.

КейсПрактика25 сентября 2026 г.9 мин

CRM-маркетолог готовит рассылку «мы скучаем» и спрашивает аналитика, кому её отправлять: всем, кто давно не покупал, или только тем, кто раньше покупал часто. Отвечает на это RFM-анализ. RFM-анализ — это способ разделить клиентов на группы по трём признакам: Recency — сколько дней прошло с последней покупки, Frequency — сколько покупок было, Monetary — сколько денег клиент принёс. Каждый признак переводят в балл, по сочетанию баллов клиенту дают сегмент — «чемпионы», «лояльные», «уходящие», «спящие» — и для каждого сегмента готовят своё действие.

Коротко

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

  • Recency считают от фиксированной опорной даты, а не от сегодняшнего дня, иначе результат меняется при каждом запуске.
  • Баллы ставят по квантилям (ntile) или по порогам из жизни бизнеса. Квантили ломаются, когда у признака мало разных значений.
  • Если средний чек у всех примерно одинаковый, Monetary повторяет Frequency и третий балл ничего не добавляет.
  • Для подписки и SaaS покупки заменяют активностью: давностью последнего входа и числом активных дней.
  • Сегмент без действия бесполезен. Для каждого нужно знать, что вы ему предложите и какую метрику будете смотреть.

Что такое Recency, Frequency и Monetary

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

Три признака RFM
ПризнакВопросКак считатьЛучший балл
Recencyкак давно клиент покупалопорная дата − дата последней покупки, в дняхменьше дней
Frequencyкак часто покупаетчисло покупок за периодбольше покупок
Monetaryсколько приноситсумма покупок за периодбольше денег

Как сделать RFM-анализ: пошагово

Порядок одинаковый в SQL, Excel и CRM. Большая часть работы — не формула, а решения до неё: что считать покупкой, за какой период и от какой даты.

  • Определите покупку: оплаченный заказ, без возвратов и отмен. Для подписки решите, считается ли автопродление покупкой.
  • Выберите период, например 12 месяцев, и опорную дату — день после последней транзакции в выгрузке.
  • Посчитайте на клиента давность, число покупок и сумму. Одна строка — один клиент.
  • Посмотрите распределение каждого признака и корреляцию частоты с суммой.
  • Поставьте баллы: квантили, если значений много, пороги, если мало или у бизнеса есть естественный цикл.
  • Сведите комбинации баллов в 5–8 сегментов с понятными названиями и для каждого запишите действие и метрику.

Как посчитать RFM в SQL: признаки

Возьмём учебную базу SQL-курса: подписочный сервис, 912 платящих клиентов, оплаты с 6 июня по 30 августа, всего $30 639. Опорная дата — день после последней оплаты в данных, max(paid_at) + 1, то есть 31 августа. Так давность у самого свежего клиента равна одному дню, и запрос даёт одинаковый результат завтра и через месяц.

Первым делом посмотрите, как распределены признаки. 622 клиента заплатили один раз, 241 — дважды, 49 — трижды. Две трети базы — одна покупка.

Частота и сумма на учебной базе
ОплатКлиентовСредняя суммаСредний платёж
1622$24,5$24,5
2241$48,7$24,4
349$74,8$24,9
Признаки RFM на клиента и проверка распределения частоты
with rfm as (
  select user_id,
         date '2026-08-31' - max(paid_at) as recency_days,   -- max(paid_at) + 1
         count(*) as frequency,
         sum(amount) as monetary
  from payments
  group by user_id
)
select frequency,
       count(*) as clients,
       round(avg(monetary), 1) as avg_monetary,
       round(avg(monetary / frequency), 1) as avg_payment
from rfm
group by frequency
order by frequency;

Monetary повторяет Frequency

Платёж в учебной базе бывает только $19, $29 или $39, и средний платёж почти не зависит от того, сколько раз клиент платил: $24,4–24,9. Поэтому сумма — это примерно частота, умноженная на $24,5. Корреляция между ними 0,81.

Что это значит на практике: балл M здесь не добавляет информации, а только удваивает вес частоты. Разница в сумме между клиентами с одинаковой частотой объясняется тарифом, а тариф — отдельный признак, его проще взять напрямую. В рознице, где чек у разных клиентов отличается в десятки раз, M работает; в подписке с тремя ценами — нет. Проверьте это до того, как строить куб 5 × 5 × 5.

Быстрая проверка перед RFM
corr(frequency, monetary) и средний чек по частоте

Если корреляция высокая, а средний чек при разной частоте одинаковый, сегментируйте по R и F, а M показывайте как выручку сегмента.

Баллы: квантили через ntile или фиксированные пороги

Учебниковый рецепт — разбить каждый признак на пять равных по численности групп функцией ntile(5). Для давности с десятками разных значений это работает: границы получаются 1–8, 8–16, 16–25, 25–41 и 41–86 дней. Правда, значения на границах — 8, 16, 25 и 41 день — попали каждое в две группы сразу: ntile режет строки, а не значения.

С частотой хуже. Разных значений три, а групп пять, поэтому клиенты с одной оплатой занимают ранги с первого по четвёртый. Какой ранг получит конкретный человек, решает порядок сортировки. Из 125 возможных комбинаций R × F × M заполнено 55, и часть различий между ними создана сортировкой, а не поведением клиентов.

Ранг F по ntile(5) и настоящее число оплат
Ранг FОплатКлиентов
11183
21183
31182
4174
42108
52133
5349
Что ntile(5) делает с частотой, у которой всего три значения
with rfm as (
  select user_id,
         date '2026-08-31' - max(paid_at) as recency_days,
         count(*) as frequency,
         sum(amount) as monetary
  from payments
  group by user_id
),
scored as (
  select *,
         ntile(5) over (order by recency_days desc, user_id) as r,
         ntile(5) over (order by frequency, user_id) as f,
         ntile(5) over (order by monetary, user_id) as m
  from rfm
)
select f, frequency, count(*) as clients
from scored
group by f, frequency
order by f, frequency;
Когда брать фиксированные пороги

Когда у признака мало разных значений или когда у бизнеса есть естественный цикл. В подписке с ежемесячной оплатой давность до 30 дней значит «оплаченный месяц ещё идёт», 31–60 — пропущено одно продление, больше 60 — два. Такие пороги понятны маркетингу и не плывут при каждом пересчёте.

RFM-сегменты: пример на SQL

Ставим R по циклу оплаты: 3 — до 30 дней, 2 — 31–60, 1 — больше 60. F — число оплат, их три значения. M в сегментацию не входит, но выручку сегмента показываем. Названия сегментов — договорённость внутри команды; важно, чтобы каждый читался как действие.

RFM-сегменты учебной базы, опорная дата 31 августа
СегментПравилоКлиентовВыручкаДавность, дней
новичкиR3, одна оплата410 (45,0%)$10 090 (32,9%)15
лояльныеR3, две оплаты183 (20,1%)$8954 (29,2%)15
чемпионыR3, три оплаты49 (5,4%)$3663 (12,0%)9
под угрозойR2, одна оплата144 (15,8%)$3566 (11,6%)44
уходящиеR1–2, две оплаты и больше58 (6,4%)$2784 (9,1%)40
спящиеR1, одна оплата68 (7,5%)$1582 (5,2%)70
RFM-сегментация по порогам из цикла подписки
with rfm as (
  select user_id,
         date '2026-08-31' - max(paid_at) as recency_days,
         count(*) as frequency,
         sum(amount) as monetary
  from payments
  group by user_id
),
scored as (
  select *,
         case when recency_days <= 30 then 3
              when recency_days <= 60 then 2
              else 1 end as r,
         least(frequency, 3) as f
  from rfm
),
segmented as (
  select *,
         case
           when r = 3 and f = 3 then 'чемпионы'
           when r = 3 and f = 2 then 'лояльные'
           when r = 3 and f = 1 then 'новички'
           when r < 3 and f >= 2 then 'уходящие'
           when r = 2 then 'под угрозой'
           else 'спящие'
         end as segment
  from scored
)
select segment,
       count(*) as clients,
       round(100.0 * count(*) / sum(count(*)) over (), 1) as clients_pct,
       sum(monetary) as revenue,
       round(100.0 * sum(monetary) / sum(sum(monetary)) over (), 1) as revenue_pct,
       round(avg(recency_days)) as avg_recency
from segmented
group by segment
order by revenue desc;

Что делать с каждым RFM-сегментом

Самый большой сегмент — новички, 410 человек. У них одна оплата не потому, что они хуже остальных, а потому что с первой оплаты не прошло месяца и продлевать ещё рано. Сравнивать их с «под угрозой» можно только через месяц, по когортам первой оплаты.

Действие и метрика для сегмента
СегментЧто делатьЧто смотреть
чемпионыне мешать: ранний доступ к функциям, просьба об отзыве или рекомендации, без скидокудержание, число приглашений
лояльныепредложить годовой тариф или переход на тариф вышедоля перешедших, выручка на клиента
новичкидовести до ключевого действия до первого продлениядоля продливших через 30 дней
под угрозойнапомнить о ценности до окончательного ухода, выяснить причинудоля вернувшихся за 30 дней
уходящиеличный контакт: эти люди уже продлевали, значит, продукт был им нужендоля вернувшихся, причины ухода
спящиедешёвая автоматическая рассылка или не трогать вовсестоимость контакта против возврата
Эффект кампании меряют с контрольной группой

Часть «уходящих» вернётся и без письма. Оставьте случайные 10–20% сегмента без рассылки и сравнивайте возврат с ними, а не с прошлым месяцем.

RFM для подписки и SaaS: активность вместо покупок

В подписке оплата происходит автоматически, и давность платежа говорит о состоянии карты больше, чем о намерениях клиента. Ранний сигнал ухода — активность в продукте. Поэтому в SaaS R и F берут из событий: R — дни с последнего входа, F — число активных дней за последние 28 дней. M остаётся тарифом.

В учебной базе повторяется только app_open, поэтому активностью считаем его. Опорная дата — тоже 31 августа, окно — с 3 по 30 августа. Отдельно отмечаем тех, у кого последняя оплата не старше 30 дней, то есть оплаченный месяц идёт.

R и F по событиям для всех пользователей и тех, кто платит сейчас
with activity as (
  select user_id,
         date '2026-08-31' - max(event_time::date) as recency_days,
         count(distinct event_time::date)
           filter (where event_time >= date '2026-08-03') as active_days_28
  from events
  group by user_id
),
paying_now as (  -- последняя оплата не старше 30 дней
  select user_id
  from payments
  group by user_id
  having date '2026-08-31' - max(paid_at) <= 30
),
scored as (
  select a.*,
         p.user_id is not null as paying_now,
         case when recency_days <= 7 then 3
              when recency_days <= 30 then 2
              else 1 end as r,
         case when active_days_28 >= 4 then 3
              when active_days_28 >= 2 then 2
              else 1 end as f
  from activity a
  left join paying_now p using (user_id)
)
select r, f,
       count(*) as users,
       count(*) filter (where paying_now) as paying_now
from scored
group by r, f
order by r desc, f desc;
  • Из 4613 пользователей 1115 заходили в последнюю неделю и не меньше четырёх дней за 28 — ядро продукта.
  • Платят сейчас 642 человека. Из них 185, то есть 28,8%, не открывали продукт больше 14 дней, а 49 — больше 30. Это главный список для команды удержания: деньги пока идут, но следующее продление под вопросом.
  • Комбинация R1 с F2 или F3 невозможна по построению: кто не заходил 30 дней, не имеет активных дней в последних 28.

Частые ошибки в RFM-анализе

Почти все ошибки делают сегменты случайными или устаревшими.

  • Одинаковые значения и ntile. Квантили режут строки, поэтому одинаковые клиенты получают разные баллы. Проверяйте распределение каждого признака и при малом числе значений ставьте пороги.
  • Большинство с одной покупкой. Если 68% клиентов купили один раз, F почти для всех одинаковый. Сегментация фактически идёт по R, и это нужно сказать заказчику.
  • Возраст клиента вместо поведения. Новичок не успел купить второй раз. Считайте F за одинаковое окно от первой покупки или сравнивайте только клиентов одного возраста.
  • Опорная дата «сегодня». При каждом запуске давность сдвигается, и сегменты меняются без изменения поведения. Фиксируйте дату и пишите её в отчёте.
  • Сегменты посчитали один раз. Люди переходят между сегментами каждый месяц. Пересчитывайте регулярно и смотрите переходы: сколько лояльных стали уходящими.
  • M без проверки. Если сумма почти равна частоте, третий балл удваивает вес частоты и ничего не объясняет.

Что читать дальше

RFM смотрит на клиента изнутри его истории. Если нужно понять, кто приносит основную долю денег, используйте ABC-анализ, а удержание по времени смотрите когортами. Попробуйте в песочнице поменять порог давности с 30 на 35 дней и посмотрите, сколько клиентов перейдёт из «под угрозой» в «новички».

Продолжить чтение
Вся библиотека
Продуктовая аналитика24 сентября 2026 г.11 мин
Однородное облако точек распадается на несколько групп разного цвета и размера

Сегментация пользователей: что это, как делить и где она обманывает

Сегментация — деление пользователей на группы по признаку, чтобы увидеть различия, которые прячет среднее. Виды сегментов, отличие сегмента от когорты, RFM-анализ в SQL, маленькие сегменты, смена состава и сегменты в A/B-тестах — на учебной базе.

Читать материал
Продуктовая аналитика24 сентября 2026 г.11 мин
Ряд одинаковых точек, из которого часть точек отделяется и уходит за край

Churn rate и retention rate: что это и как посчитать отток

Churn rate — доля клиентов, которые ушли за период, из тех, кто был в его начале. Как посчитать отток клиентов и retention rate в подписке и в бесплатном продукте, чем customer churn отличается от revenue churn, как перевести месячный отток в годовой и где ошибаются со знаменателем.

Читать материал