Từ những khách hàng tiêu dùng lớn cho đến những khách hàng rời bỏ doanh nghiệp, tất cả những khách hàng đều có nhu cầu và mong muốn đa dạng. Doanh nghiệp muốn khách hàng chi tiêu nhiều hơn từ những chiến dịch tiếp thị chương trình, sản phẩm mới tới khách hàng theo những cách khác nhau. Tuy nhiên, câu hỏi đặt ra là làm thế nào để đưa ra được các chiến dịch tiếp thị phù hợp với những nhóm khách hàng đang có nhu cầu để từ đó tăng tỷ lệ phản hồi từ khách hàng và từ đó tăng doanh số bán hàng. Bài toán đặt ra là làm thế nào để có thể phân khúc khách hàng một cách tương đối chính xác dựa trên hành vi giao dịch lịch sử của khách hàng, thuật toán RFM sẽ giúp chúng ta giải quyết vấn đề này một cách nhanh chóng và hiệu quả.
Phân tích RFM là một kĩ thuật phân khúc khách hàng dựa trên hành vi giao dịch của khách hàng trong quá khứ, RFM bao gồm 3 chỉ số chính:
Lợi ích của phân tích RFM:
Để thực hiện phân tích RFM, giả sử chúng ta chia khách hàng thành các nhóm khác nhau theo phân phối (phân vị) cho tần suất chi tiêu, lần chi tiêu cuối cùng, và tổng số tiền chi tiêu.
Giả sử, mỗi nhóm biến chúng ta chi thành các mức phân vị khách nhau, nếu:
Khi số nhóm nhiều lên, việc quả n lý các phân khúc là điều khó khăn cho doanh nghiệp. Chúng ta xét ví dụ hành vi chiêu tiêu của khách hàng A: - Khách hàng nằm trong nhóm người mua gần đây nhất (R = 1) - Khách hàng nằm trong nhóm người mua với số lượng nhiều nhất (F = 1) - Khách hàng nằm trong nhóm người chi tiêu tiêu nhiều nhất (M = 1)
Từ đây, ta xác định được khách hàng A này thuộc phân khúc RFM (111) là nhóm khách hàng tốt nhất, dưới đây là một bảng miêu tả các phân khúc chính đối với RFM (tham khảo):
Phân khúc | RFM | Mô ta ̉ | Chương trình MKT |
---|---|---|---|
Best Customer | 111 | Những khách hàng đã mua gần đây nhất, thường xuyên nhất và chi tiêu nhiều nhất | Sản phẩm mới, chương trình khách hàng thân thiết |
Loyal Customer | X1X | Khách hàng mua gần đây nhất | Sử dụng R và M để phân khúc tiếp theo |
Big Spenders | XX1 | Khách hàng chi tiêu nhiều nhất | Tiếp thị cho họ những sản phẩm đắt nhất của doanh nghiệp |
Almost Lost | 311 | Không được mua trong một thời gian, nhưng mua thường xuyên và chi tiêu nhiều nhất | Ưu đãi về giá để họ tiếp tục sử dụng |
Lost Customers | 411 | Không được mua trong một thời gian, nhưng mua thường xuyên và chi tiêu nhiều nhất | Ưu đãi về giá để họ tiếp tục |
Lost Cheap Customers | 444 | Lần mua cuối cùng từ rất lâu, số tiền giao dịch ít và số lần giao dịch ít | Không nên tập trung vào nhóm khách này |
# Bước 1: Connect R với SQL server
# install.packages('RODBC')
library(RODBC)
library(dplyr)
library(ggplot2)
library(extrafont)
my_font <- "OfficinaSansITC"
# test <- odbcConnect('test',
# uid = 'sa', # User SQL server
# pwd = 'Dangvu257@') # # Password SQL server
#
# # Kéo 1 bảng dữ liệu từ SQL vào R...
# df <- sqlQuery(test,"select * From RFM_MODEL..FCT_RFM_MODEL
# where 1 = 1
# and MONTH_ID = '20180331'
# and CUSTOMER_GENDER in ('MALE','FEMALE')
# ")
df1 <- readRDS(file = 'D:\\VUDT\\8.TRAINING\\Chart\\RFM_DATE.RDD')
# Pareto chart
df <-
df1 %>%
group_by(CUSTOMER_SEGMENTATION) %>%
summarise(mpg_sum = sum(AMOUNT_TOT)) %>%
ungroup() %>%
mutate(mpg_sum = round(mpg_sum/1e9)) %>%
arrange(mpg_sum) %>%
as.data.frame() %>%
mutate(mpg_cumsum = cumsum(mpg_sum),
mpg_total = sum(mpg_sum)) %>%
mutate(mpg_percent = mpg_cumsum/mpg_total) %>%
mutate(mpg_int = seq(1:NROW(.)))
# Chart
nr <- nrow(df)
N <- sum(df$mpg_sum)
df_ticks <- data.frame(xtick0 = rep(nr +.55, 11), xtick1 = rep(nr +.59, 11),
ytick = seq(0, N, N/10))
y2 <- paste0(seq(0, 100, 10), '%')
ggplot(df, aes(x = reorder(CUSTOMER_SEGMENTATION,mpg_cumsum), y = mpg_sum)) +
geom_bar(stat="identity", fill = "#23576E", width = 0.5) +
geom_line(aes(x = mpg_int, y = mpg_cumsum), color = "#8C3F4D") +
geom_point(aes(x = reorder(CUSTOMER_SEGMENTATION,mpg_cumsum), y = mpg_cumsum), color = "#8C3F4D", pch = 19) +
scale_y_continuous(breaks=seq(0, N, N/10), limits=c(-.02 * N, N * 1.02)) +
scale_x_discrete(breaks = df$CUSTOMER_SEGMENTATION) +
guides(fill = FALSE, color = FALSE) +
annotate("rect", xmin = nr + .55, xmax = nr + 1, ymin = -.02 * N, ymax = N * 1.02,
fill = "#EFF2F4") +
annotate("text", x = nr + .8, y = seq(0, N, N/10), label = y2, size = 3, family="serif") +
# geom_segment(x = nr + .55, xend = nr + .55, y = -.02 * N, yend = N * 1.02, color = "grey50") +
# geom_segment(data = df_ticks, aes(x = xtick0, y = ytick, xend = xtick1, yend = ytick)) +
labs(title = "T\u00D4\u0309NG DOANH S\u00D4\u0301 GIAO DI\u0323CH\n THEO T\u01AF\u0300NG PH\u00C2N KHU\u0301C",
y = "",
x = "",
subtitle = "Tha\u0301ng ba\u0301o ca\u0301o: 31-03-2018") +
theme_bw() +
theme(text = element_text(family = 'serif')) +
theme(axis.title = element_text(family = my_font,size = 10)) +
theme(panel.background = element_blank(),
panel.grid = element_blank(),
axis.ticks = element_blank(),
# axis.text.x = element_blank(),
axis.text.x = element_text(size = 10, face = 'bold',angle = 90, vjust = -0.0),
panel.border = element_blank(),
plot.margin = unit(c(1,4,1,4), "cm"),
axis.title = element_text(family = my_font,size = 16),
text = element_text(family = 'serif')) +
theme(title = element_text(size = 10),
plot.subtitle=element_text(size = 12, hjust=0.77, face = 'italic', color="black")) +
theme(plot.title = element_text(hjust = 0.5,face = 'bold')) +
theme(plot.background = element_rect(fill = "#EFF2F4", color = NA)) +
theme(panel.background = element_rect(fill = "#EFF2F4", color = NA)) +
theme(legend.background = element_rect(fill = "#EFF2F4", color = NA))
USE [RFM_MODEL]
GO
/****** Object: StoredProcedure [dbo].[PCD_DIM_COHORT_TOTAL] Script Date: 5/27/2019 11:50:55 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: <VU DANG,>
-- Create date: <2019/05/17,,>
-- Description: <COHORT TOTAL,,>
-- Ref: https://rstudio-pubs-static.s3.amazonaws.com/365184_904c4/*
369586e49fc8fa08adcae1d559d.html
-- =============================================
ALTER PROCEDURE [dbo].[PCD_DIM_COHORT_TOTAL]
-- Add the parameters for the stored procedure here
@DATE VARCHAR(8)
AS
BEGIN
SET NOCOUNT ON;
-- Insert statements for procedure here
-- STEP 1: TẠO DANH SÁCH KHÁCH HÀNG BAN ĐẦU --- THÁNG 01/01/2017 - 30/11/2017 (REPORT_MONTH 2017/12)
DROP TABLE IF EXISTS #step1_customer_original
SELECT DISTINCT CUSTOMER_CARD
INTO #step1_customer_original
FROM DATA_RAW..card_transaction_sb_201701_201803
WHERE 1 = 1
AND DAYID BETWEEN DATEADD(m, DATEDIFF(m, 0, DATEADD(month, -11, @DATE)), 0) AND EOMONTH(DATEADD(month, -11, @DATE))
--AND DAYID BETWEEN DATEADD(month, -12, @DATE) AND DATEADD(month, -11, @DATE)
-- BƯỚC 2: TẠO COHORT TRONG 12 THÁNG
DROP TABLE IF EXISTS #STEP2_CUSTOMER_COHORT ;
SELECT
CONVERT(VARCHAR(6),DAYID,112) AS COHORT_ID,
COUNT(DISTINCT CUSTOMER_CARD) AS NUMBER,
CONVERT(VARCHAR(6),@DATE,112) MONTH_ID
INTO #STEP2_CUSTOMER_COHORT
FROM DATA_RAW..card_transaction_sb_201701_201803 A
WHERE 1 = 1
AND DAYID BETWEEN DATEADD(m, DATEDIFF(m, 0, DATEADD(month, -11, @DATE)), 0) AND @DATE
--AND DAYID BETWEEN DATEADD(month, -12, @DATE) AND @DATE
--AND YEAR(DAYID) = 2017
AND CUSTOMER_CARD IN (SELECT CUSTOMER_CARD from #step1_customer_original)
GROUP BY CONVERT(VARCHAR(6),DAYID,112)
ORDER BY COUNT(DISTINCT CUSTOMER_CARD) DESC;
/*
DROP TABLE IF EXISTS RFM_MODEL..DIM_COHORT
CREATE TABLE RFM_MODEL..DIM_COHORT (
MONTH_ID VARCHAR(8),
COHORT_ID VARCHAR(6),
RETENTION FLOAT,
RETENTION_RATE FLOAT
)
*/
DELETE FROM RFM_MODEL..DIM_COHORT WHERE MONTH_ID = @DATE
INSERT INTO RFM_MODEL..DIM_COHORT (
MONTH_ID,
COHORT_ID,
RETENTION
)
SELECT
@DATE MONTH_ID,
COHORT_ID,
NUMBER
FROM #STEP2_CUSTOMER_COHORT
-- TÍNH RETENTION_RATE
UPDATE RFM_MODEL..DIM_COHORT
SET RETENTION_RATE = ROUND(A.RETENTION/B.RETENTION_MAX,2)
FROM RFM_MODEL..DIM_COHORT A, (SELECT MAX(RETENTION) RETENTION_MAX FROM RFM_MODEL..DIM_COHORT WHERE MONTH_ID = @DATE ) B
WHERE A.MONTH_ID = @DATE
END
*/