Как посчитать RFM-сегментацию в SQL

Закрепи формулу rfm segmentation в Карьернике
Запомнить надолго — 5 коротких сессий с задачами на эту тему. Бесплатно
Тренировать rfm segmentation в Telegram

Зачем RFM

RFM-сегментация — простой и эффективный способ разделить customers на группы для marketing. «Champions» (high R+F+M) ≠ «At Risk» (low R, был F+M). Разные actions для каждого segment.

Формула

Recency  = дней с последней покупки (меньше = лучше)
Frequency = кол-во покупок за период
Monetary  = revenue за период

R/F/M score = NTILE(5) каждого
RFM_score   = R*100 + F*10 + M (например, 555 — best)

Базовый расчёт

WITH user_rfm AS (
    SELECT
        user_id,
        EXTRACT(DAY FROM CURRENT_DATE - MAX(created_at))::INT AS recency_days,
        COUNT(*) AS frequency,
        SUM(total) AS monetary
    FROM orders
    WHERE status = 'paid'
      AND created_at >= CURRENT_DATE - INTERVAL '365 days'
    GROUP BY user_id
),
rfm_scored AS (
    SELECT
        user_id,
        recency_days,
        frequency,
        monetary,
        NTILE(5) OVER (ORDER BY recency_days)         AS r_score,
        NTILE(5) OVER (ORDER BY frequency DESC)       AS f_score,
        NTILE(5) OVER (ORDER BY monetary DESC)        AS m_score
    FROM user_rfm
)
SELECT
    user_id,
    r_score,
    f_score,
    m_score,
    r_score * 100 + f_score * 10 + m_score AS rfm_score
FROM rfm_scored
ORDER BY rfm_score DESC;

NTILE: 1 — best 20%, 5 — worst 20%. Note: для recency меньше = лучше, поэтому ORDER BY recency_days ASC.

Сегменты

Стандартные RFM-сегменты:

Segment R F M Описание
Champions 5 5 5 Топ-клиенты
Loyal Customers 4-5 4-5 3-5 Высокая частота + monetary
Potential Loyalists 3-5 1-3 1-3 Recent buyers с low frequency
At Risk 2-3 4-5 4-5 Высокий F/M, но давно не покупали
Lost 1-2 1-2 1-2 Низкий по всем
WITH scored AS (
    -- ... (RFM scoring выше)
)
SELECT
    user_id,
    CASE
        WHEN r_score >= 4 AND f_score >= 4 AND m_score >= 4 THEN 'Champions'
        WHEN r_score >= 4 AND f_score >= 3 THEN 'Loyal'
        WHEN r_score >= 3 AND f_score <= 3 THEN 'Potential'
        WHEN r_score <= 3 AND f_score >= 4 THEN 'At Risk'
        WHEN r_score <= 2 AND f_score <= 2 THEN 'Lost'
        ELSE 'Other'
    END AS segment
FROM scored;
Закрепи формулу rfm segmentation в Карьернике
Запомнить надолго — 5 коротких сессий с задачами на эту тему. Бесплатно
Тренировать rfm segmentation в Telegram

Применение

  • Champions: VIP-программа, exclusive deals.
  • Loyal: referral incentives.
  • Potential: cross-sell, increase frequency.
  • At Risk: win-back campaigns, discounts.
  • Lost: aggressive re-engagement или write off.

Частые ошибки

Ошибка 1. NTILE на equal values. Если много users с same monetary, NTILE assignment может быть suboptimal.

Ошибка 2. RFM score без context. 255 vs 552 — same numbers, different segments. Use named segments, not raw score.

Ошибка 3. Window mismatch. Recency считается от today. Если данные «застывшие» — recency меняется без real change.

Ошибка 4. Period for F+M. 30, 90, 365 days? Период должен соответствовать продукту.

Ошибка 5. Применять без personalization. Champions получают spam discounts → их LTV падает. Champions нужны exclusive offers, не commodity.

Связанные темы

FAQ

Why NTILE(5) and not NTILE(10)?

NTILE(5) проще для interpretation: 5 buckets. NTILE(10) — granularity, но 1000 categories total.

RFM для B2B?

Работает, но adjust: F и M по аккаунтам, не users.

RFM static или dynamic?

Динамичный. Re-calculate weekly / monthly.

How to update segments?

Standard: weekly. High-frequency продукт: daily.

RFM vs ML segmentation?

RFM — простой и interpretable. ML — точнее, но black-box.