[Tech Blog #25 | Data Analytics] Phân Khúc Khách Hàng Với Mô Hình RFM: Tư Duy Định Lượng & Kỹ Thuật NTILE Trong SQL
![[Tech Blog #25 | Data Analytics] Phân Khúc Khách Hàng Với Mô Hình RFM: Tư Duy Định Lượng & Kỹ Thuật NTILE Trong SQL](/uploads/ai-images/cover-phan-khuc-khach-hang-rfm.png)
1. Đặt vấn đề: Cái bẫy của việc "Đối xử với mọi khách hàng như nhau"
Đã bao giờ bạn nhận được tin nhắn quảng cáo: "Tặng voucher 10.000đ cho đơn hàng tiếp theo" từ một nhãn hàng mà bạn vừa chi 50 triệu đồng để mua sắm tuần trước?
Hoặc ngược lại: Một khách hàng đã 2 năm không mở app bỗng nhiên nhận được email chúc mừng: "Cảm ơn bạn đã luôn đồng hành cùng chúng tôi"?
Đây là hậu quả của việc doanh nghiệp đối xử cào bằng với mọi khách hàng:
- Khách hàng VIP chi hàng trăm triệu không nhận được đặc quyền tương xứng.
- Khách hàng sắp rời bỏ (At-risk) không được cứu vãn kịp thời.
- Ngân sách khuyến mãi (Voucher/Discount) bị rải mành mành vô ích cho những người chỉ thích săn sale giá rẻ mà không bao giờ quay lại.
Quy luật Pareto 80/20 chỉ ra rằng: Khoảng 20% lượng khách hàng trung thành thường đóng góp tới 80% tổng doanh thu của công ty.
Để tìm ra 20% khách hàng vàng này và biết chính xác cần phải làm gì với 80% còn lại, Data Analyst sử dụng một khung phân tích định lượng kinh điển: Mô hình RFM (Recency, Frequency, Monetary).
2. Giải mã 3 trụ cột của Mô hình RFM
RFM phân tích hành vi lịch sử giao dịch của từng khách hàng dựa trên 3 câu hỏi cốt lõi:
[RECENCY (R) - Độ mới] ──> Lần mua hàng gần nhất cách đây bao nhiêu ngày?
(Càng mới mua gần đây -> Điểm R càng cao)
[FREQUENCY (F) - Tần suất] ──> Khách hàng đã phát sinh tổng cộng bao nhiêu đơn hàng?
(Càng mua nhiều lần -> Điểm F càng cao)
[MONETARY (M) - Giá trị] ──> Khách hàng đã chi tiêu tổng cộng bao nhiêu tiền?
(Tổng chi tiêu càng lớn -> Điểm M càng cao)
Thang điểm từ 1 đến 5:
Chúng ta chia tập khách hàng thành 5 nhóm bằng nhau (mỗi nhóm 20%) cho từng chỉ số bằng cách cho điểm từ 1 (kém nhất) đến 5 (tốt nhất):
- Điểm R (1 đến 5): Khách mới mua hôm qua Điểm R = 5; Khách mua lần cuối từ 1 năm trước Điểm R = 1. (Lưu ý: Số ngày càng nhỏ thì điểm R càng cao!)
- Điểm F (1 đến 5): Mua 20 đơn Điểm F = 5; Mua đúng 1 đơn duy nhất Điểm F = 1.
- Điểm M (1 đến 5): Chi tiêu 100 triệu Điểm M = 5; Chi tiêu 100 nghìn Điểm M = 1.
Mỗi khách hàng sẽ có một mã định danh 3 chữ số, ví dụ: 555 (Khách VIP tuyệt đối) hoặc 155 (Khách xịn nhưng sắp mất vào tay đối thủ!).
3. Bản đồ ma trận phân khúc khách hàng & Hành động kinh doanh
| Nhóm khách hàng | Đặc điểm điểm RFM | Trạng thái hành vi | Hành động chiến lược đề xuất |
|---|---|---|---|
| Champions (Khách hàng VIP) | R: 4-5, F: 4-5, M: 4-5 | Mua gần đây, mua thường xuyên, chi tiền khủng. | Chăm sóc 1-1, mời trải nghiệm sản phẩm mới sớm, không cần tặng voucher giảm giá sâu. |
| Loyal Customers (Trung thành) | R: 3-4, F: 4-5, M: 3-5 | Mua đều đặn, giá trị tốt, gắn bó lâu dài. | Chương trình tích điểm thành viên, gợi ý bán kèm (Cross-sell/Up-sell). |
| Potential Loyalists (Tiềm năng) | R: 4-5, F: 2-3, M: 2-4 | Khách mới mua gần đây, chi tiêu khá, có triển vọng. | Gửi email hướng dẫn sử dụng, tặng voucher cho đơn thứ 2 để tạo thói quen. |
| At Risk (Nguy cơ rời bỏ) | R: 1-2, F: 4-5, M: 4-5 | Từng mua rất nhiều tiền nhưng đã lâu không quay lại! | Báo động đỏ! Gọi điện CSKH hỏi thăm, gửi ưu đãi cá nhân hóa đặc biệt để kéo họ quay lại. |
| Hibernating / Lost (Ngủ đông) | R: 1-2, F: 1-2, M: 1-2 | Đã rất lâu không mua, chỉ mua 1 lần giá trị thấp. | Chạy chiến dịch email tự động chi phí thấp, nếu không phản hồi thì loại khỏi danh sách gửi tin để tiết kiệm ngân sách. |
4. Thực hành thực chiến: Xây dựng Pipeline RFM hoàn chỉnh bằng SQL
Sử dụng CTE ([Tech Blog #17]) kết hợp hàm phân vị NTILE(5) trong SQL để phân nhóm khách hàng tự động:
-- Giả sử thời điểm chốt sổ phân tích là ngày 2026-09-30
WITH raw_rfm AS (
-- Bước 1: Tính toán các giá trị thô R, F, M cho từng khách hàng
SELECT
customer_id,
-- Recency: Số ngày kể từ lần mua gần nhất đến ngày chốt sổ
DATE_PART('day', '2026-09-30'::TIMESTAMP - MAX(order_date)) AS recency_days,
-- Frequency: Tổng số đơn hàng đã hoàn thành
COUNT(order_id) AS frequency_orders,
-- Monetary: Tổng số tiền đã chi tiêu
SUM(total_amount) AS monetary_value
FROM
orders
WHERE
status = 'COMPLETED'
GROUP BY
customer_id
),
rfm_scores AS (
-- Bước 2: Dùng hàm NTILE(5) chia đều thành 5 bậc điểm từ 1 đến 5
SELECT
customer_id,
recency_days,
frequency_orders,
monetary_value,
-- Recency: Số ngày càng nhỏ thì điểm càng cao -> Dùng ORDER BY DESC để đảo ngược
NTILE(5) OVER (ORDER BY recency_days DESC) AS r_score,
-- Frequency & Monetary: Càng lớn điểm càng cao
NTILE(5) OVER (ORDER BY frequency_orders ASC) AS f_score,
NTILE(5) OVER (ORDER BY monetary_value ASC) AS m_score
FROM
raw_rfm
),
segmented_customers AS (
-- Bước 3: Ghép điểm và gán nhãn phân khúc bằng CASE WHEN
SELECT
customer_id,
recency_days,
frequency_orders,
monetary_value,
r_score,
f_score,
m_score,
-- Ghép chuỗi điểm: ví dụ '555', '155'
CONCAT(r_score, f_score, m_score) AS rfm_combined,
-- Gán nhãn phân khúc kinh doanh
CASE
WHEN r_score >= 4 AND f_score >= 4 AND m_score >= 4 THEN '1. Champions (VIP)'
WHEN r_score >= 3 AND f_score >= 3 AND m_score >= 3 THEN '2. Loyal Customers'
WHEN r_score >= 4 AND f_score <= 2 THEN '3. New / Potential Loyalists'
WHEN r_score <= 2 AND f_score >= 4 AND m_score >= 4 THEN '4. At Risk (Nguy cơ rời bỏ)'
WHEN r_score <= 2 AND f_score <= 2 THEN '5. Lost / Hibernating'
ELSE '6. Average Customers'
END AS customer_segment
FROM
rfm_scores
)
-- Bước 4: Thống kê tổng hợp số lượng và doanh thu theo từng phân khúc
SELECT
customer_segment,
COUNT(customer_id) AS total_customers,
ROUND(AVG(recency_days)::NUMERIC, 1) AS avg_recency_days,
ROUND(AVG(frequency_orders)::NUMERIC, 1) AS avg_orders,
ROUND(SUM(monetary_value)::NUMERIC, 0) AS total_revenue_vnd,
ROUND(
(SUM(monetary_value) / SUM(SUM(monetary_value)) OVER ()) * 100,
2
) AS revenue_contribution_pct
FROM
segmented_customers
GROUP BY
customer_segment
ORDER BY
total_revenue_vnd DESC;
5. Câu hỏi phỏng vấn thực tế (Interview Q&A)
Câu 1 (Mức độ: Entry / Junior)
Câu hỏi: "Mô hình RFM là gì? Tại sao chúng ta không phân loại khách hàng dựa trên một chỉ số duy nhất là Tổng chi tiêu (Monetary) cho đơn giản?"
Gợi ý trả lời:
"RFM phân loại khách hàng dựa trên 3 chiều: Độ mới (Recency), Tần suất (Frequency) và Tổng chi tiêu (Monetary).
Nếu chỉ dùng duy nhất chỉ số Monetary, chúng ta sẽ rơi vào điểm mù thời gian:
Một khách hàng từng chi 100 triệu mua hàng nhưng đã cách đây 3 năm và hiện đã chuyển sang mua của đối thủ vẫn sẽ bị xếp chung nhóm VIP với một khách hàng tuần nào cũng chi 5 triệu đều đặn.
Nhờ có thêm chiều Recency, chúng ta phân biệt được ngay: Ai là VIP đang hoạt động tích cực (R=5, M=5) và ai là VIP đang có nguy cơ rời bỏ (R=1, M=5) để kịp thời tung ra chiến dịch chăm sóc khách hàng cứu vãn doanh thu."
Câu 2 (Mức độ: Junior / Mid-level)
Câu hỏi: "Trong thực tế, khi dữ liệu bị lệch mạnh (ví dụ 75% khách hàng chỉ mua đúng 1 lần duy nhất), việc dùng hàm NTILE(5) trên cột Frequency sẽ gặp lỗi gì và cách xử lý chuẩn là gì?"
Gợi ý trả lời:
*"HàmNTILE(5)cố gắng chia đều số dòng dữ liệu thành 5 nhóm có số lượng bằng nhau (mỗi nhóm 20%). Khi 75% khách hàng đều có cùng giá trịfrequency = 1, hàm NTILE buộc phải chia các khách hàng có cùng giá trị 1 đơn này vào cả nhóm điểm 1, điểm 2 và điểm 3 một cách ngẫu nhiên. Điều này làm cho hai khách hàng có hành vi giống hệt nhau (đều mua 1 đơn) lại nhận điểm F khác nhau, gây sai lệch phân tích.
Cách xử lý chuẩn:
Thay vì dùng phân vị tương đốiNTILE, chúng ta sẽ chuyển sang dùng Ngưỡng cố định theo nghiệp vụ (Rule-based Thresholds) bằng mệnh đềCASE WHEN:
- F=1: Mua đúng 1 đơn.
- F=2: Mua 2–3 đơn.
- F=3: Mua 4–6 đơn.
- F=4: Mua 7–10 đơn.
- F=5: Mua trên 10 đơn.
Cách này đảm bảo tính nhất quán tuyệt đối về mặt hành vi kinh doanh."*
6. Key Takeaways (Ghi nhớ nhanh)
- RFM là vũ khí chống lãng phí: Giúp doanh nghiệp chi tiền khuyến mãi đúng người, đúng thời điểm thay vì giảm giá đại trà.
- Quy tắc tính điểm Recency: Số ngày càng ít Khách mua càng gần đây Điểm càng cao (Dùng
ORDER BY recency_days DESCtrongNTILE). - Cảnh giác cao độ với nhóm At Risk (R=1, F=5, M=5): Đây là những khách hàng giá trị cao sắp rời bỏ, cần ưu tiên nguồn lực chăm sóc hàng đầu.
- Kết hợp NTILE và Ngưỡng thực tế: Dùng NTILE khi dữ liệu phân phối đều; dùng
CASE WHENphân ngưỡng khi dữ liệu bị tập trung quá nhiều vào một giá trị duy nhất.