RFM是什么
在CRM系統中經常要對用戶進行劃分,以標記不同的標簽,進行個性化的營銷觸達動作。通常的用戶群體劃分會使用用戶的一些屬性信息,例如年齡,職業,性別等。但是這些屬性基本上都是用戶本身的特征屬性,并不是和品牌關聯產生的屬性信息。另外一種常用的用戶模型,就是RFM模型,是以用戶的實際購買行為數據作為基礎,進行用戶群體的劃分的,在實踐中更加具有實際價值。
RFM模型由三個指標組成,分別為:
最近一次消費 (Recency)
消費頻率 (Frequency)
消費金額 (Monetary)
可以看到這三個屬性都是通過用戶的購買行為計算得出的,這些指標基本上代表了用戶是否活躍,購買能力,忠誠度等信息。
而我們的目標是通過對每個用戶的RFM屬性進行計算,將用戶群體劃分為不同的種類進行區分,以便我們進行分析和精準營銷。例如我們可以分析出高價值用戶,重點發展用戶,流失用戶等群體進行針對性營銷動作。
本文將使用Python的一些工具包,對用戶數據集進行分析處理,例如建立RFM模型,數據標準化,以及使用k-means聚類算法將用戶群體進行劃分。需要讀者具有一些基礎的Python和數據統計知識。
通過數據建立RFM模型
首先我們通過一些訂單數據分析得到一部分用戶的樣本數據來:
user_id,total_order_count,total_order_price,last_order_date
161526959,1,11878,2017-07-13 19:22:43.0
38972904,1,20735,2017-08-11 00:51:06.0
136664518,1,12680,2017-02-26 10:48:20.0
3921846,3,24722,2017-08-17 23:31:49.0
103291929,6,218720,2018-02-12 14:17:54.0
71742617,1,8919,2018-01-10 00:57:43.0
15114544,1,2935,2017-02-17 15:57:25.0
......
這里包括了用戶的id,總購買筆數,總購買金額以及最后一筆訂單時間的信息。我們將文件加載進來,截取一部分后對字段類型進行處理:
import pandas as pd
import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
df = pd.read_csv('./membersData.csv')
df = df.drop(df.index[5000:])
df['last_order_date'] = pd.to_datetime(df['last_order_date'])
為了將其轉化為我們要使用的RFM屬性,我們需要對last_order_date進行處理,轉換為最后一次訂單時間到目前的天數。這樣我們就獲得了RFM的基本屬性,分別為last_order_day_from_now(R), total_order_count(F), total_order_price(M)。處理完成后對數據進行可視化觀察數據分布:
df['last_order_day_from_now'] = (pd.to_datetime('today') \
- df['last_order_date']).dt.days
df.plot.scatter(x='last_order_day_from_now',
y='total_order_count',
c='total_order_price',
cmap='viridis_r', s=50);
其散點圖為:
我們會發現實際上的數據大部分都聚集在了一起,并且有一些非常離散的極端值數據,這對我們后續進行數據聚類會產生不利影響,所以我們使用log函數對數據進行處理,讓其分布的更加均勻:
df['total_order_count_log'] = np.log10(df['total_order_count'])
df['total_order_price_log'] = np.log10(df['total_order_price'])
df['last_order_day_from_now_log'] = np.log10(
df['last_order_day_from_now'])
df.plot.scatter(x='last_order_day_from_now_log',
y='total_order_count_log',
c='total_order_price_log',
cmap='viridis_r', s=50);
可以看到現在數據分布的已經比較均勻了,這為我們進行聚類打下一個比較好的基礎。但同時我們也會發現RFM這三個屬性的單位卻并不相同,分別是天數,交易筆數和交易金額。這就造成了其數值差別巨大。而聚類算法一般都是使用不同向量間的距離進行計算劃分的,屬性單位不同造成的數值差異過大會造成計算距離時的權重分布不均衡,也并不能反映實際情況,所以我們還要對數據進行標準化處理,這里我們使用z-score對RFM屬性進行加工運算。
z-score是一種數據標準化的計算方法,其公式為:
z = (x – μ) / σ
μ代表x所屬數據組的平均值,σ代表x所屬數據組的方差。所以通過z-score計算,我們將絕對值數據轉化為一個數據在所屬數據組中的位置(得分),這樣不同單位和類型間的數據使用z-score做相互的比較也就有了一定的意義。
df['total_order_count_zscore'] = stats.zscore(df['total_order_count_log'])
df['total_order_price_zscore'] = stats.zscore(df['total_order_price_log'])
df['last_order_day_from_now_zscore'] = stats.zscore(
df['last_order_day_from_now_log'])
df.plot.scatter(x='last_order_day_from_now_zscore',
y='total_order_count_zscore',
c='total_order_price_zscore',
cmap='viridis_r', s=50);
這時候會看到數據不但分布較為均勻,而且不同維度間的數值差異也很小了,這樣我們可以把三種不同單位的屬性一起進行處理。
基于RFM模型對用戶數據進行分類
當我們建立好RFM的數據模型之后,期望通過不同的RFM值,對用戶進行區分以進行精準化營銷。當然我們可以通過對RFM這三組數值的平均值或者中位數和每個用戶進行比較,以建立起一個數據立方,進行群體劃分。但另外一方面,一般來說用戶群體會大致符合28原則,80%左右的收入是由20%左右的客戶所貢獻的,所以根據平均值或者中位數進行群體劃分也并不能總是科學的反應出不同的用戶群體來,所以我們也可以基于數據本身的特性,使用聚類算法進行處理,以便讓數據更加“自然”的區分。
這里我們選用非常常用的k-means算法進行聚類計算,k-means聚類的原理并不復雜,首先隨機的或者通過更高效的方式(例如k-means++)選取k個點,然后不斷迭代的計算,修正這k個點的坐標,目的是讓集合中的每個點的距離(有很多種距離算法,比較常用的是歐氏距離)都和k個點里的其中一個盡量的近,而和其他的盡量的遠。這樣數據集合就能根據自身的分布規律,自然的區分出不同的類別來。
from sklearn.cluster import KMeans
sampleArray = df.iloc[:,8:].values
kmeans = KMeans(n_clusters=3, random_state=0).fit(sampleArray)
df.plot.scatter(x='last_order_day_from_now_zscore',
y='total_order_count_zscore',
c=kmeans.labels_,
cmap='viridis_r',
norm=None, s=50);
這里我們將k值設定為3,也就是將數據劃分為三個部分,通過使用我們處理后的RFM屬性進行計算,最終我們得到:
可以看到不同的顏色代表不同的用戶類別,可以簡單的認為標記為0的是流失用戶,1是重點發展用戶,2是高價值用戶。這樣我們就可以對不同的群體使用適合的營銷策略了,同時當有新的用戶加入后,我們也可以使用得到的k-means模型對其進行預測劃分。
可能遇到的問題
在使用這種方式做實際的數據處理時,可能因為數據分布的原因導致區分度并不是特別好,因為根據銷售數據進行用戶區分,并不是總能發現比較明顯的區分“界限”,也就是不同群體間的邊界其實是非常模糊和混雜的(從上面的最終分析圖也可以看出這樣的情況),所以從這個角度講,單純通過RFM模型和聚類進行用戶群體劃分也是有它的局限性的。