背景
RFM(Recency Frequency Monetary)模型是衡量客戶價(jià)值和客戶創(chuàng)利能力的重要工具和手段。在眾多的客戶關(guān)系管理(CRM)的分析模式中,RFM模型是被廣泛提到的。
RFM模型是屬于業(yè)務(wù)分析方法與模型中的部分。它的本質(zhì)是用戶分類。本文將用現(xiàn)代最流行的編程語言---Python語言來實(shí)踐課堂上講解的RFM模型,將用戶進(jìn)行分類。
本文采用Anaconda進(jìn)行Python編譯,主要涉及的Python模塊:
-
pandas
-
matplotlib
-
seaborn
-
datetime
本章分為三部分講解:
1.RFM模型原理與步驟
2.Python分布實(shí)現(xiàn)RFM
3.總結(jié)
RFM模型原理與步驟
RFM模型的思路是:該模型是根據(jù)用戶歷史行為數(shù)據(jù),結(jié)合業(yè)務(wù)理解選擇劃分維度,實(shí)現(xiàn)用戶分類,助力用戶精準(zhǔn)營銷。此外,還學(xué)習(xí)了構(gòu)建RFM模型的步驟:
-
獲取R、F、M三個(gè)維度下的原始數(shù)據(jù)
-
定義R、F、M的評估模型與判斷閾值
-
進(jìn)行數(shù)據(jù)處理,獲取R、F、M的值
-
參照評估模型與閾值,對用戶進(jìn)行分層
-
針對不同層級用戶制定運(yùn)營策略
上面步驟可以知道,我們需要有RFM三個(gè)維度,根據(jù)我們在業(yè)務(wù)分析方法課程中學(xué)到的,業(yè)務(wù)分析模型離不開指標(biāo),而指標(biāo)是對度量的匯總。因此,在找出RFM三個(gè)維度后,需要對每個(gè)維度下度量實(shí)現(xiàn)不同匯總規(guī)則。下面講述對R、F、M三個(gè)維度下的度量如何進(jìn)行匯總。
1.R代表最近一次消費(fèi),是計(jì)算最近一次消費(fèi)時(shí)間點(diǎn)和當(dāng)前時(shí)間點(diǎn)的時(shí)間差。因此,這里需要用到多維數(shù)據(jù)透視分析中的基本透視規(guī)則---最小值MIN求出最小的時(shí)間差。
2.F代表消費(fèi)頻次,是在指定區(qū)間內(nèi)統(tǒng)計(jì)用戶的購買次數(shù)。因此,這里需要用到多維數(shù)據(jù)透視分析中的基本透視規(guī)則---技術(shù)類COUNT(技術(shù)類不去重指標(biāo))統(tǒng)計(jì)用戶的購買次數(shù)。
3.M代表消費(fèi)金額,是指在指定區(qū)間內(nèi)統(tǒng)計(jì)用戶的消費(fèi)總金額,因此,這里需要用到求和類指標(biāo),也即基本透視規(guī)則中的合計(jì)規(guī)則---SUM。
在對得到RFM模型中的指標(biāo)值后最重要的一步就是分層,根據(jù)我們在課堂上學(xué)到的內(nèi)容,大部分的用戶分層是根據(jù)經(jīng)驗(yàn)來分層的,本文在追求數(shù)據(jù)的客觀性下采取統(tǒng)計(jì)學(xué)中的等距分箱方法來進(jìn)行分層,對R、F、M三個(gè)維度分成兩類。
綜上,我們大致了解了如何構(gòu)建RFM模型,下面以Python實(shí)現(xiàn)RFM模型,并對每一步進(jìn)行詳細(xì)的講解。
03 Python實(shí)現(xiàn)RFM模型
數(shù)據(jù)準(zhǔn)備
本文所需的數(shù)據(jù)是一家公司對2021年10月底至今的客戶購買行為數(shù)據(jù),(前十二行)如圖下:
其中,uid
代表客戶的id,是存在重復(fù)情況的。prince
維度代表客戶每發(fā)生一次交易行為所花費(fèi)的金額。time
為客戶發(fā)生交易行為的時(shí)間。
數(shù)據(jù)讀取與理解
在得到一份數(shù)據(jù)之后,我們第一步就是要理解數(shù)據(jù)的業(yè)務(wù)意義,以及對數(shù)據(jù)表的EDA(探索性分析),這里通過如下代碼,發(fā)現(xiàn)以下特征:
具體代碼(包含Python導(dǎo)入包部分)如下:
#導(dǎo)入相關(guān)包
importpandasaspd
importtime
importnumpyasnp
importseabornassns
importmatplotlib.pyplotasplt
plt.rcParams['font.sans-serif']=["SimHei"]
plt.rcParams["axes.unicode_minus"]=Falsesns.set(style="darkgrid")
#數(shù)據(jù)讀取與查看
data=pd.read_excel('data.xlsx')
data.head()
data.isnull().sum()#查看缺失值
data.duplicated().sum()#重復(fù)值,但是不刪
data.dtypes#查看數(shù)據(jù)類型
data.describe()
#創(chuàng)建dataframe,存放RFM各值
data_rfm=pd.DataFrame()
接下來進(jìn)行R、F、M指標(biāo)值構(gòu)建。
時(shí)間維度處理
從上文可以知道time
維度,即每筆交易行為發(fā)生的時(shí)間是字符串object的格式,而在Python中我們對時(shí)間作差需要的是datetime
格式,因此利用pandas
庫中的pd.to_datetime
函數(shù)將時(shí)間格式進(jìn)行轉(zhuǎn)換,代碼如下:
data['time']=pd.to_datetime(data['time'])
得到的前五行數(shù)據(jù)如圖下,可以看到數(shù)據(jù)類型變成了datetime64[ns]
統(tǒng)計(jì)每筆訂單產(chǎn)生時(shí)間與當(dāng)前時(shí)間的差(這里的當(dāng)前時(shí)間是2021年12月11日),得到的差是timedelta64[ns]
類型
可以看到時(shí)間差中包含了day、時(shí)、分、秒4個(gè)維度,但是這里我們僅需要day維度,因此我們用astype()
函數(shù)將類型轉(zhuǎn)為僅含有day維度的timedelta64[D]
類型。具體代碼如下:
#統(tǒng)計(jì)沒條數(shù)據(jù)與當(dāng)前日期的時(shí)間差
##計(jì)算相差天數(shù)
data['R']=(pd.datetime.now()-data['time'])
##將時(shí)間差timedelta格式轉(zhuǎn)化為需要的日格式
data['R']=data['R'].astype('timedelta64[D]').astype('int')
(tips:這里可能會(huì)報(bào)警告:FutureWarning: The pandas.datetime class is deprecated and will be removed from pandas in a future version. Import from datetime module instead.
讀者無需理會(huì),這是由于我們所用的pd.datetime.now()
是一個(gè)比較舊的函數(shù),以后將會(huì)廢棄。)
統(tǒng)計(jì)R值
在上面我們已經(jīng)創(chuàng)建了名為data_rfm
的表結(jié)構(gòu)的數(shù)據(jù)框,因此,將下面統(tǒng)計(jì)的R值放入其中。R值得統(tǒng)計(jì)是找客戶最近發(fā)生交易行為日期與當(dāng)前日期的差。換一種思路就是找所有時(shí)間差中的最小值。
因此利用pandas
中的groupby
函數(shù)對每個(gè)用戶以上一步統(tǒng)計(jì)的R值作為分組依據(jù)進(jìn)行分組,并求出最小值。具體代碼如下:
data_rfm=pd.merge(data_rfm,data.groupby('uid')['R'].min(),
left_on='user_id',right_on='uid')
統(tǒng)計(jì)F值
F值得統(tǒng)計(jì)就是統(tǒng)計(jì)指定區(qū)間內(nèi)的消費(fèi)頻次,而指定區(qū)間一般為人為設(shè)定,這里我們?nèi)∪繑?shù)據(jù),即2021年10月底至今作為指定區(qū)間。
本文利用value_counts()
函數(shù)對uid
進(jìn)行統(tǒng)計(jì)即為每個(gè)用戶得消費(fèi)頻次,同時(shí)將結(jié)果合并到data_rfm
數(shù)據(jù)框中。
#統(tǒng)計(jì)指定區(qū)間內(nèi)的消費(fèi)頻次
data_rfm['user_id']=data['uid'].value_counts().index
data_rfm['F']=data['uid'].value_counts().values
統(tǒng)計(jì)M值
本文以uid
作為分組依據(jù)對price
字段進(jìn)行求和,得到求和類指標(biāo)M值。此外,將結(jié)果合并到data_rfm
數(shù)據(jù)框中。
data_rfm=pd.merge(data_rfm,data.groupby('uid')['price'].sum(),
left_on='user_id',right_on='uid')
data_rfm.rename(columns={'price':'M'},inplace=True)
上述代碼中出現(xiàn)了pandas
庫中得合并語法merge()
,merge()
函數(shù)采取的是橫向合并,不同于MYSQL,不需要指定左表還是右表為主表,只需要提供左表與右表的公共字段在各表中的名稱即可。
由于data_rfm
數(shù)據(jù)表中的user_id
是去重的,因此將其作為主鍵。而data.groupby('uid')['price'].sum()
得到的表格也是去重的,因此我們可以采取多維數(shù)據(jù)模型中的連接對應(yīng)關(guān)系---一對一對兩表進(jìn)行合并。公共字段為:左表的uid
,右表的user_id
。
最終表格結(jié)果如下,展現(xiàn)前18行:
數(shù)據(jù)分箱
在得到R、F、M三個(gè)指標(biāo)值后,我們需要對這三個(gè)指標(biāo)進(jìn)行分類,并將每個(gè)用戶進(jìn)行分層。
本文不采取人為主觀性的經(jīng)驗(yàn)法則劃分,而是采取等距分箱的方式劃分,等距分箱的原理較簡單,這里寫出步驟:
-
從最小值到最大值之間,均分為$N$等份(這里$N$取為2)。
-
如果 $A$,$B$ 為最小最大值, 則每個(gè)區(qū)間的長度為 $W=(B?A)/N$ ,.
-
則區(qū)間邊界值為$A+W$,$A+2W$,….$A+(N?1)W$ 。這里只考慮邊界,采用左閉右開的方式,即每個(gè)等份的實(shí)例數(shù)量不等。
在Python中可以利用pandas
庫中的cut()
函數(shù)輕松實(shí)現(xiàn)上述等距分箱,同時(shí)將結(jié)果R_label
,F_label
,M_label
合并到data_rfm
數(shù)據(jù)框中具體代碼如下:
#分箱客觀左閉右開
cut_R=pd.cut(data_rfm['R'],bins=2,right=False,labels=range(1,3)).astype('int')
data_rfm['R_label']=cut_R
cut_F=pd.cut(data_rfm['F'],bins=2,right=False,labels=range(1,3)).astype('int')
data_rfm['F_label']=cut_F
cut_M=pd.cut(data_rfm['M'],bins=2,right=False,labels=range(1,3)).astype('int')
data_rfm['M_label']=cut_M
由于利用cut()
函數(shù)得到的是區(qū)間形式的值,因此需要賦予label值進(jìn)行虛擬變量引用。label值使用1和2,對應(yīng)的區(qū)間為從小到大。具體代表意思如下表:
得到最終的表格形式如下:
用戶分類
在得到每個(gè)用戶的R、F、M三個(gè)維度的label值后,最后就是需要對用戶進(jìn)行分類,分類的原則如圖下:
利用pandas庫中的·terrows()
函數(shù)循環(huán)遍歷每個(gè)用戶行為記錄,將符合上述條件的劃分對應(yīng)的類,具體代碼如下:
fori,jindata_rfm.iterrows():
ifj['R_label']==2andj['F_label']==2andj['M_label']==2:
data_rfm.loc[i,'用戶類別']='重要價(jià)值用戶'
ifj['R_label']==2andj['F_label']==1andj['M_label']==2:
data_rfm.loc[i,'用戶類別']='重要發(fā)展用戶'
ifj['R_label']==1andj['F_label']==2andj['M_label']==2:
data_rfm.loc[i,'用戶類別']='重要保持用戶'
ifj['R_label']==1andj['F_label']==1andj['M_label']==2:
data_rfm.loc[i,'用戶類別']='重要挽留用戶'
ifj['R_label']==2andj['F_label']==2andj['M_label']==1:
data_rfm.loc[i,'用戶類別']='一般價(jià)值用戶'
ifj['R_label']==2andj['F_label']==1andj['M_label']==1:
data_rfm.loc[i,'用戶類別']='一般發(fā)展用戶'
ifj['R_label']==1andj['F_label']==2andj['M_label']==1:
data_rfm.loc[i,'用戶類別']='一般保持用戶'
ifj['R_label']==1andj['F_label']==1andj['M_label']==1:
data_rfm.loc[i,'用戶類別']='一般挽留用戶'
條形圖可視化用戶類別
利用seaborn
畫圖庫對已劃分類別的用戶進(jìn)行技術(shù)統(tǒng)計(jì)與可視化,得到如下圖表
可以看出,大部分的用戶屬于一般發(fā)展用戶與一般挽留用戶。而對于一般發(fā)展用戶而言采取的策略為挖掘需求,后者則是放棄治療。因此,可以看出該公司在10月底至今的時(shí)間段內(nèi),用戶流失較多,但是可發(fā)展的用戶同樣是非常多的,想要提高收入,對一般發(fā)展用戶入手是成本少,效率高的選擇。
總結(jié)
RFM模型同時(shí)還利用了多維數(shù)據(jù)透視分析和業(yè)務(wù)分析方法兩個(gè)模塊的內(nèi)容。所以說實(shí)踐是檢驗(yàn)和鞏固學(xué)到的東西的最好方法。
例如一級的??碱}上,我們常碰到一個(gè)模擬題,包含RFM模型劃分規(guī)則和一張帕累托圖,問題是在公司有限成本下提高公司收入,需要針對哪種用戶營銷最好,答案是一般發(fā)展用戶。相信大家一開始都很疑惑為什么選這個(gè),這時(shí)候如果像本文一樣對一份數(shù)據(jù)進(jìn)行實(shí)踐,這樣你就會(huì)更加理解為什么是這個(gè)答案。
審核編輯:郭婷
-
python
+關(guān)注
關(guān)注
53文章
4753瀏覽量
84076
原文標(biāo)題:基于客觀事實(shí)的 RFM 模型(Python 代碼)
文章出處:【微信號:DBDevs,微信公眾號:數(shù)據(jù)分析與開發(fā)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論