常貴客?新客? 讓RFM模型簡簡單單解釋一切!
(附實現程式碼)

在行銷資料科學裡,有項工具可協助公司找出 R「新客」(近期有消費的人)、 F 「常客」(常常來消費的人)、與 M「貴客」(消費金額大的人),這項工具稱為「RFM模型」。

RFM模型是由喬治·卡利南(George Cullinan)於1961年所提出,他發現資料庫分析中,有三項重要的指標:最近一次消費(Recency)、消費頻率(Frequency)、與消費金額(Monetary),這三項指標的英文字母的分別為R、F、M,所以就稱為「RFM模型」。

Credit:張庭瑄
接下來,我們將介紹RFM模型的簡單概念:

1. 一次消費(Recency):
指消費者至今再次購買與上次購買產品的時間差,舉例來說,將「購買日期分為五等分」,每一等分為資料庫的20%:

  • 最近消費的前20%,編碼為5
  • 20%~40%編碼為4,以此類推
  • 到80%~100%編碼為1。

也就是編碼等級越高的消費者重複購買比率較高

2. 消費頻率(Frequency):
指消費者在一定期間內購買該產品的次數。舉例來說:

  • 次數最多的前20%,編碼為5
  • 20%~40%編碼為4,以此類推
  • 80%~100%編碼為1。

編碼等級越高的消費者,其消費頻率越高,忠誠度與顧客價值也越高

3. 消費金額(Monetary):
指消費者在一定期間內購買該產品的總金額

  • 金額最大的前20%,編碼為5
  • 20%~40%編碼為4,以此類推
  • 80%~100%編碼為1。

編碼等級越高的消費者,其消費金額越高,顧客價值也越高。

利用以上的編碼方式,我們可以將顧客,依(R,F,M)的分數,共分成125群,亦即從最低的(1,1,1)(3分)到最高的(5,5,5)(15分)。

RFM模型能協助企業區分顧客,並預測每種顧客類型的消費者行為。當企業對顧客進行分群後,再進一步從公司的顧客資料庫中,分析各群顧客背後的消費者行為,進而發展預測模式。讓公司的顧客關係管理(CRM)系統在應用上,能夠提升到策略性的層級。

RFM模型實戰去!
接下來的範例,我們將會使用R語言展示如何使用RFM模型在「最近一次消費(Recency)」及「消費頻率(Frequency)」的分析應用,會使用R與F的主要原因,是因為「最近一次消費(R)」的期間,關乎消費者的存留狀況,以及「消費頻率(F)」影響顧客的顧客生命週期。所以我們會依照R與F將顧客分類成不同客群,並觀察其與產品、銷售之間的關係,以達到下列目的:
  1. 了解目前銷售狀況。
  2. 有效的運用行銷預算,在對的產品上花對的錢。
  3. 對不同的客群給予不同的優惠。
  4. 增加顧客生命週期,培養每一位顧客成為忠實/常貴客 。
我們即將使用某一匿名賣場的資料,並挑選出其中三件商品,切入R及F的模型分析。讀者可以想一下,當我們賣場內部資料有:
  1. 交易代號(orderId)
  2. 顧客編號(clientId)
  3. 產品(product)
  4. 性別(gender)
  5. 最後交易日期(orderdate)
那我們就要開始問自己幾個問題:應該從資料中擷取何種價值? 到底應該如何透過這些資料,讓手上的資源分配更有利? 我的顧客針對不同產品有偏好? 不同的顧客到底應該多銷售哪種產品?
那…既然這些問題都可以透過R及F的模式來做簡單的分析,到底R及F本身的性質是什麼?
其實,說穿了,就是我們在基礎敘述性統計中時常看到的「交叉分析」
什麼? 交叉分析就可以解決並增加營收? 是的!
資料:

首先讓我們來看看本次賣場的資料型態。本次資料共4402筆資料,可在我們提供的檔案連結下載數據

部份原始資料的具體模樣:

原始資料的模樣,product部份礙於賣場揭露之限制,所以僅取產品大分類。

將原始資料轉換成R與F模型可分析的形式

# 載入library
library(dplyr)
library(reshape2)
library(ggplot2)
library(stringr)
# start from here
orders = read.csv('orders.csv')
orders$orderdate = as.Date(orders$orderdate, origin="2017-01-01")
# 報告日期
today <- as.Date('2017-04-11', format='%Y-%m-%d')

# 資料處理
orders <- dcast(orders, orderId + clientId + gender + orderdate ~ product, value.var='product', fun.aggregate=length)

orders <- orders %>%
  group_by(clientId) %>%
  mutate(frequency=n(),
         recency=as.numeric(today-orderdate)) %>%
  filter(orderdate==max(orderdate)) %>%
  filter(orderId==max(orderId)) %>%
  ungroup()

R與F模型分析:

從F與R圖上,很明顯可以發現,最近1天內消費與最近3天內消費的消費者,在購買量上,擁有極大的差距,但是最近76天內消費跟88天內消費的消費者在購買量上,並沒有差距。這就是為何我們要畫出這兩張長條圖來決定交叉分析時「不同邊界」的原因。
所以我們就可以開始定義每個群體的邊界,而尋找邊界的方式可以利用上述F與R的分佈圖或結合業務方面的知識分析來定義不同的級距。

  本次我們的邊界根據r與f的圖來判斷每一間隔的級距定義之:

  1. 頻率分布邊界:1, 2, 3, 4, 5, >5
  2. 近因分布邊界:0–7, 8–15, 16–22, 23–30, 31–55, >55 
於是我們就可以立即製作出R與F的「交叉分析」:
上述釋例如果能利用圖形化的方式呈現,可更有效提升判斷力:
#繪製出RF分佈圖

howard_theme <- function(base_size = 12, base_family = "sans"){
  theme_minimal(base_size = base_size, base_family = base_family) +
    theme(
      axis.text.x = element_text(size=20, angle = 65, vjust = 1, hjust=1),
      axis.text.y = element_text(size=20),
      axis.title = element_text(size = 20),
      panel.grid.major = element_line(color = "grey"),
      panel.grid.minor = element_blank(),
      panel.background = element_rect(fill = "aliceblue"),
      strip.background = element_rect(fill = "navy", color = "navy", size = 1),
      strip.text = element_text(face = "bold", size = 10, color = "white"),
      legend.position = "right",
      legend.justification = "bottom",
      legend.background = element_blank(),
      legend.text=element_text(size=15),
      panel.border = element_rect(color = "grey", fill = NA, size = 0.05),
      title = element_text(size = 15),
      plot.caption=element_text(size = 10)
    )
}

#消費頻率與訂單數量分佈圖
ggplot(orders, aes(x=frequency)) +
  #theme_bw() +
  scale_x_continuous(breaks=c(1:10)) +
  geom_histogram(alpha=0.6, binwidth=1) +
  ggtitle("消費頻率與訂單數量分佈圖")+
  xlab("消費頻率") + 
  ylab("訂單數量") +howard_theme()+
  theme(plot.title = element_text(color="red", size=30),
      axis.title.x = element_text(color="blue", size=20),
      axis.title.y = element_text(color="#993333", size=20))

#R頻率分佈圖
ggplot(orders, aes(x=recency)) +
  theme_bw() +
  geom_histogram(alpha=0.6, binwidth=1) +
  scale_x_continuous(breaks=c(0:91))+
  ggtitle("最近一次(天)的消費與購買量分佈圖")+
  xlab("距離上次購買的天數") + 
  ylab("訂單數量") +#howard_theme()+
  theme(plot.title = element_text(color="red", size=30),
        axis.title.x = element_text(color="blue", size=20),
        axis.title.y = element_text(color="#993333", size=20),
        panel.background = element_rect(fill = "aliceblue"),
        strip.background = element_rect(fill = "navy", color = "navy", size = 1),
        strip.text = element_text(face = "bold", size = 10, color = "white"))


# 切割頻率
orders.segm <- orders %>%
  mutate(buy_freq=ifelse(between(frequency, 1, 1), '1',
                          ifelse(between(frequency, 2, 2), '2',
                                 ifelse(between(frequency, 3, 3), '3',
                                        ifelse(between(frequency, 4, 4), '4',
                                               ifelse(between(frequency, 5, 5), '5', '>5')))))) %>%
  
  
  # 切割近因畫出邊界
  mutate(segm.rec=ifelse(between(recency, 0, 7), '0-7 天',
                         ifelse(between(recency, 8, 15), '8-15 天',
                                ifelse(between(recency, 16, 22), '16-22 天',
                                       ifelse(between(recency, 23, 30), '23-30 天',
                                              ifelse(between(recency, 31, 55), '31-55 天', '>55 天')))))) %>%
  # 把商品放入變數中
  mutate(cart=paste(ifelse(瓶裝水!=0, '、瓶裝水', ''),
                    ifelse(牛奶麵包!=0, '、牛奶麵包', ''),
                    ifelse(高麗菜!=0, '、高麗菜', ''), sep='')) %>%
  arrange(clientId)

# '瓶裝水','牛奶麵包','高麗菜'
# 定義邊界的順序
orders.segm$buy_freq <- factor(orders.segm$buy_freq, levels=c('>5', '5', '4', '3', '2', '1'))
orders.segm$segm.rec <- factor(orders.segm$segm.rec, levels=c('>55 天', '31-55 天', '23-30 天', '16-22 天', '8-15 天', '0-7 天'))
orders.segm$cart = str_split_fixed(orders.segm$cart, '、', 2)[,2]

lcg <- orders.segm %>%
  group_by(segm.rec, buy_freq) %>%
  summarise(quantity=n()) %>%
  mutate(client='顧客人數') %>%
  ungroup()

lcg.matrix= as.data.frame.matrix(table(orders.segm$buy_freq, orders.segm$segm.rec))
lcg.matrix$buy_freq = row.names(lcg.matrix) 
lcg.matrix

# 繪製RFM分析圖
lcg.adv <- lcg %>%
  mutate(rec.type = ifelse(segm.rec %in% c(">55 天", "31-55 天", "23-30 天"), "not recent", "recent"),
         freq.type = ifelse(buy_freq %in% c(">5", "5", "4"), "frequent", "infrequent"),
         customer.type = interaction(rec.type, freq.type))

ggplot(lcg.adv, aes(x=client, y=quantity, fill=customer.type)) +
  theme_bw() +
  theme(panel.grid = element_blank()) +
  geom_rect(aes(fill = customer.type), xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = Inf, alpha = 0.1) +
  facet_grid(buy_freq ~ segm.rec) +
  geom_bar(stat='identity', alpha=0.7) +
  geom_text(aes(y=max(quantity)/2, label=quantity), size=4) +
  ggtitle("R與F分析圖") +
  xlab("最近一次消費天數") + ylab("購買頻率")+ 
  theme(plot.title = element_text(color="red", size=30 ),
        axis.title.x = element_text(color="blue", size=20, face="bold"),
        axis.title.y = element_text(color="#993333", size=20, face="bold"))+
  guides(fill=guide_legend(title="客群顏色指示表"))+
  scale_fill_discrete(name="Experimental\nCondition",breaks = c('not recent.frequent','recent.frequent','not recent.infrequent','recent.infrequent'), labels = c('先前客','常貴客','一次性消費客人','新顧客'))

lcg.sub <- orders.segm %>%
  group_by(gender, cart, segm.rec, buy_freq) %>%
  summarise(quantity=n()) %>%
  mutate(client='顧客人數') %>%
  ungroup()
圖片X軸為距離最近一次消費天數(R),而Y軸為購買頻率(F),表格內方塊的數字則表示顧客人數,人數越多方塊內的顏色堆疊越多,並且顏色將顧客區隔分成四大類:
  1. 綠色區塊:常貴客;在短時間內頻頻來光顧,他們是最重要的顧客,它們在短時間內已經來訪許多次了,也是忠實老顧客,是公司主要的客源。
  2. 紫色區塊:新顧客;來訪的頻率不是特別高,也許是第一次來或者只是一次性消費的客人,但其中還是有潛力成為常貴客,所以行銷方向要以「產品導向」導入他們進入常貴客群為主。
  3. 紅色區塊:先前客;他們對於一般的公司來說,是長時間內,營收最大的來源,公司必須要持續吸引他們,讓他們能於「更短時間內」再至來訪,重新產生購買,否則有可能會漸漸流失。
  4. 藍色區塊:一次性消費客人;若此區塊比例偏多,代表來過的客人都不會來第二次。
相信讀者閱讀至此,已經有了顧客區分的概念,接下來便可以針對不同的客群使用不同的行銷手段、價格、優惠,以達到最終目的!那分隔區塊內能不能再依照不同人口變數或產品區分呢?
當然可以! 接下來就讓我們「交叉再交叉」,進行子區段分析(Sub-segments analysis):
# 繪製RFM分析圖(性別分類)  fill=
lcg.sub$gender = factor(lcg.sub$gender, levels = c('女性', '男性'))
ggplot(lcg.sub, aes(x=client, y=quantity, fill=gender)) +
  theme_bw() +
  scale_fill_brewer(palette='Set1') +
  theme(panel.grid = element_blank())+
  geom_bar(stat='identity', position='fill' , alpha=0.6) +
  facet_grid(buy_freq ~ segm.rec) +
  ggtitle("R與F分析圖(性別)") +
  xlab("最近一次消費天數") + ylab("購買頻率")+ 
  theme(plot.title = element_text(color="red", size=30),
        axis.title.x = element_text(color="blue", size=20, face="bold"),
        axis.title.y = element_text(color="#993333", size=20, face="bold"))+
  guides(fill=guide_legend(title="顧客性別"))

R與F分析圖(性別分類)

我們先將性別(gender)來做區隔,紅色區塊是女性,藍色區塊是男性,如果我們僅看最重要的常貴客分群,由R與M分析圖(性別分類)可以看出一很有趣的現象,購買頻率在0–7天內平均大於5次為男性居多,但剛好等於5次的則是女性居多。
這時候讀者一定會問一個問題:「So what? 那接下來我該怎做? 能更吸引這群人來購買?」這時候我們就要再從性別切出更細更產品類別:
# 繪製RFM分析圖(商品分類)
ggplot(lcg.sub, aes(x=gender, y=quantity, fill=cart)) +
  theme_bw() +
  scale_fill_brewer(palette='Set1') +
  theme(panel.grid = element_blank())+
  geom_bar(stat='identity', position='fill' , alpha=0.6) +
  facet_grid(buy_freq ~ segm.rec) +
  ggtitle("R與F分析圖(商品分類)") +
  xlab("最近一次消費天數") + ylab("購買頻率")+ 
  theme(plot.title = element_text(color="red", size=30),
        axis.title.x = element_text(color="blue", size=20, face="bold"),
        axis.title.y = element_text(color="#993333", size=20, face="bold"))+
  guides(fill=guide_legend(title="商品顏色指示表"))
  
再來我們將性別分類及商品分類最重要的「常貴客」4區塊特別擷取下來比較:
這時候要推薦何種商品便一目了然~! 讀者可以想想,如果你是行銷資料科學家或專業經理人,有了這些資料,應該如何分配這一家店的資源?
首先,我們先從性別分類圖來看:
0–7天內大於5次購買頻率的多為男生,女生次之
  1. 男生喜好購買的優先順序為「瓶裝水、高麗菜」的組合及「瓶裝水、高麗菜、牛奶麵包」的組合。
  2. 女生則優先順序為「瓶裝水、牛奶麵包」的組合及「瓶裝水、高麗菜、牛奶麵包」。
0–7天內等於5次購買頻率的多為女生,男生次之
  1. 男生喜好購買的優先順序為「瓶裝水、高麗菜」的組合及「瓶裝水、高麗菜、牛奶麵包」的組合。
  2. 女生則優先順序為「瓶裝水、牛奶麵包」的組合、「瓶裝水、高麗菜、牛奶麵包」且單獨的「瓶裝水」產品。
8–15天內大於5次購買頻率的多為女生,男生次之
  1. 男生喜好購買的優先順序為「瓶裝水、牛奶麵包」的組合。這群男生僅喜好一種組合,如果要讓這群男生逐漸轉變為0–7天消費,商家可以考慮在有利潤的情形下,對「瓶裝水、高麗菜」及「瓶裝水、高麗菜、牛奶麵包」的組合進行行銷活動,讓這群男生逐漸變成0–7天消費5次以上,賺取更多營收。
  2. 女生則優先順序為「瓶裝水、牛奶麵包」的組合、「瓶裝水、高麗菜、牛奶麵包」。
恩…還是沒感覺嗎? 讓我們用「8–15天內大於5次購買頻率的男性顧客」算給您看,假設這群男生有200人,平均11.5天消費7.5次,而「瓶裝水、牛奶麵包」的組合利潤為100,平均每天可以達到
一天200人平均消費=(7.5/11.5)*200人=130.4348
每天利潤=100* 130.4348= 13043.48元
如果對「瓶裝水、高麗菜」及「瓶裝水、高麗菜、牛奶麵包」的組合進行行銷活動,舉例來說,「打折促銷」。
瓶裝水、高麗菜=250元原利潤經過7折轉換=145
瓶裝水、高麗菜、牛奶麵包=210元原利潤79折轉換=105
200人因收到該折扣而到0-7天的轉換率 = 200人 * 20% = 40人
這200人因為此行銷活動,為公司帶來的每天總利潤
8–15天內大於5次購買頻率:(7.5次/11.5天)*160人*100= 10,435
40人轉到「0–7天內大於5次購買平率」:(7.5次/5天)*15人*145+ (7.5次/5天)*25人*105=7,200

所以40人轉換,每天就賺 10,435 +7,200=17,635,比起原本的13,044,每天還要多賺4,591。如果經濟、品牌等因素狀況不變

一個月就多賺137,730,這是將近14萬元阿!

一年就差了168萬阿!

這就是R與F模型的厲害之處! 至於消費金額(Monetary)的部分將於往後的文章中進行說明。
 由此可見R與F分析技術可以有效率地將數據結合,並可在子段進行無限的變化,就有很大的機會可以賺取更多的營收,只要有顧客相關的資料,例如:職業、住址、甚至興趣習慣等…,再配合上業務方面知識分析,便可製作出有指標性的視覺化資料,並且調整銷售策略。

敬請期待!時間序列與顧客終生價值分析

共同作者:
鍾皓軒(臺灣行銷研究有限公司 共同創辦人)
羅凱揚(台科大兼任助理教授)
楊超霆(臺灣行銷研究有限公司 資料科學研發工程師)

Scroll to Top