5.7案例:基於RFM的精細化用戶管理
案例背景:在用戶2015-2018年訂單數據的基礎上,對用戶進行分羣,總結每個組用戶特徵,以便於精細化運營,制定定製化和差異性的營銷和關懷;
分析思路:基於RFM對用戶進行分羣,將三個維度分別作三個區間的離散化
import time
import numpy as np
import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from pyecharts.charts import Bar3D
import pyecharts.options as opts
sheet_names = ["2015","2016","2017","2018","會員等級"]
sheet_datas = [pd.read_excel(r"D:\data_analysis_and_data_operation_with_python\python_book_v2\chapter5\sales.xlsx",sheet_name=i) for i in sheet_names]
#查看各個表是否存在缺失值
#for i in sheet_datas:
# print(i.info())
for each_name,each_data in zip(sheet_names,sheet_datas):
print("[data summary for {0:=^50}]".format(each_name))
print("Overview:","\n",each_data.head())
print("DESC:","\n",each_data.describe())
print("NA records",each_data.isnull().any(axis=1).sum())
#數據均可以讀取,無格式錯誤。缺失值總共只有一個,可以直接刪除,其次訂單金額分佈極不均衡,根據業務背景,極大值產生是合理的(有貴重商品),其次金額小於1的訂單,沒有實際意義;
#處理缺失值和刪除訂單金額小於1的數據
for ind,each_data in enumerate(sheet_datas[:-1]):
sheet_datas[ind] = each_data.dropna()
sheet_datas[ind] = each_data[each_data["訂單金額"]>1]
#便於計算,最近一購買時間間隔
sheet_datas[ind]["max_years_date"] = each_data["提交日期"].max()
#將年份數據進行縱向合併
data_merge = pd.concat(sheet_datas[:-1],axis=0)
#獲取購買時間與年末的差值(最近一次購買),獲取購買年份
data_merge["date_interval"] = data_merge["max_years_date"] - data_merge["提交日期"]
data_merge["year"] = data_merge["提交日期"].dt.year
#date_interval時間戳轉化爲數字
data_merge["date_interval"] = data_merge["date_interval"].apply(lambda x:x.days)
#提取“購買金額”,“購買次數”,“最近一次購買”時間字段,有兩種方法,數據透視表以及groupby
#rfm_gb = pd.pivot_table(data_merge,index=["year","會員ID"],values=["訂單號","訂單金額","date_interval"],aggfunc=
# {"訂單號":"count","訂單金額":"sum","date_interval":"min"}).reset_index()
rfm_gb = data_merge.groupby(["year","會員ID"],as_index=False).agg({
"date_interval":"min",
"提交日期":"count",
"訂單金額":"sum"})
rfm_gb.columns=["year","會員ID","r","f","m"]
#查看屬性分佈
rfm_gb[["r","f","m"]].describe()
r | f | m | |
count | 148591 | 148591 | 148591 |
mean | 165.524043 | 1.365002 | 1323.741329 |
std | 101.988472 | 2.626953 | 3753.906883 |
min | 0 | 1 | 1.5 |
25% | 79 | 1 | 69 |
50% | 156 | 1 | 189 |
75% | 255 | 1 | 1199 |
max | 365 | 130 | 206251.8 |
數據解讀,最近一次購買時間分佈較爲均勻,購買頻率大部分用戶爲一次,主要是因爲行業屬性(大家電)原因,用戶一年購買一次較爲普遍,那麼最近一次購買時間分佈均爲也是此原因,可以認爲家電購買時間隨機分佈;(個人感覺將最近一次購買時間作爲重要指標不合適)
#臨界點劃分,r和m以四分位點劃分即可,f則以[0,2,5,130]進行劃分;
#定義區間邊界,注意最小值,python進行區間分割時,是左開右閉區間
r_bins = [-1,79,255,365]
f_bins = [0,2,5,130]
m_bins = [-1,69,1199,206252]
#確定rfm因子權重,基於會員等級給予權重
rfm_merge = pd.merge(rfm_gb,sheet_datas[-1],on="會員ID",how="inner")
clf = RandomForestClassifier()
clf = clf.fit(rfm_merge[["r","f","m"]],rfm_merge["會員等級"])
weights = clf.feature_importances_
#rfm分箱,並將分類屬性轉化爲數值屬性
rfm_gb["r_score"] = pd.cut(rfm_gb["r"],r_bins,labels = [i for i in range(len(r_bins)-1,0,-1)])
rfm_gb["f_score"] = pd.cut(rfm_gb["f"],f_bins,labels = [i+1 for i in range(len(f_bins)-1)])
rfm_gb["m_score"] = pd.cut(rfm_gb["m"],m_bins,labels = [i+1 for i in range(len(m_bins)-1)])
#計算RFM加權得分
rfm_gb = rfm_gb.apply(np.int32)
rfm_gb["rfm_score"] = rfm_gb["r_score"]*weights[0] + rfm_gb["f_score"]*weights[1]+rfm_gb["m_score"]*weights[2]
#計算RFM組合分羣,
rfm_gb["r_score"] = rfm_gb["r_score"].astype(np.str)
rfm_gb["f_score"] = rfm_gb["f_score"].astype(np.str)
rfm_gb["m_score"] = rfm_gb["m_score"].astype(np.str)
rfm_gb["rfm_group"] = rfm_gb["r_score"].str.cat(rfm_gb["f_score"]).str.cat(rfm_gb["m_score"])
#保存數據文件
rfm_gb.to_excel(r"D:\data_analysis_and_data_operation_with_python\sales_rfm_score.xlsx")
#RFM圖形展示,只展示年份,rfm分組,用戶數量
display_data = rfm_gb.group_by(["rfm_group","year"],as_index=False)["會員ID"].count()
display_data.columns = ["rfm_group","year","number"]
display_data["rfm_group"] = display_data["rfm_group"].astype(np.int32)
#畫圖
bar3d = Bar3D(init_opts=opts.InitOpts(width="900px", height="600px"))
range_color = ["#313695","#4575b4","#74add1","#abd9e9","#e0f3f8","#ffffbf",
"#fee090","#fdae61","#f46d43","#d73027","#a50026"]
bar3d.add(
series_name="rfm分組結果",
data = [d.tolist() for d in display_data.values]
).set_global_opts(
visualmap_opts=opts.VisualMapOpts(
max_=display_data["number"].max(),
range_color=range_color,
))
bar3d.render(r"D:\data_analysis_and_data_operation_with_python\sales_rfm_score.html")
結果分析:
用戶標籤 | 用戶數量佔比 | 用戶消費金額佔比 | 運營思路 |
212 | 24.79% | 5.58% | 可發展的一般性羣體,通過運營手段維持並提升其消費狀態 |
211 | 12.80% | 0.32% | 可發展的低價值羣體,通過運營手段提升其購買金額 |
312 | 12.55% | 2.86% | 有潛力的一般性羣體,購買新近度高,單忠誠度一般,通過其最近購買的商品,推薦相關商品 |
112 | 11.34% | 2.53% | 可挽回的一般性羣體,通過多種方式觸達客戶並挽回 |
213 | 11.02% | 31.48% | 可發展的高價值羣體,發展重點是提高其購物頻率 |
311 | 6.24% | 0.16% | 有潛力的低價值羣體,可以通過分析其渠道,加大相應渠道的投入,引導客戶復購 |
111 | 6.14% | 0.16% | 各個維度都比較差的羣體,主要通過多種策略挽回客戶(資源足夠的情況下) |
313 | 5.61% | 16.57% | 有潛力的高價值羣體,發展重點是提高其購物頻率 |
113 | 5.07% | 14.19% | 可挽回的高價值羣體,可適當的進行人工介入 |
123 | 1.30% | 4.80% | |
333 | 0.33% | 4.53% | 絕對忠誠的高價值各戶,應爲其提供相應的VIP服務 |
233 | 0.70% | 9.21% | 一般性的高價值客戶,重點在於提升新近購買度 |
133 | 0.32% | 4.66% | |
223 | 0.25% | 1.33% | |
322 | 0.28% | 0.09% | 有潛力的普通羣體,需要提升購買頻次,和額度 |
323 | 0.25% | 1.14% | |
332 | 0.02% | 0.01% |
總結:1,個人認爲該案例數據不太實用RFM模型,因爲數據北京是大家電行業,大型的家用電器一般屬於耐用品,屬於絕對的低頻消費,因此在購買頻次這個指標很難看出客戶的價值,其次也很難通過運營提高購買頻次;最近的購買時間也是如此,如果你購買的時間越短,反而不會再進行購買;是否可以根據產品的生命週期,提醒客戶更新換代,並推出相應的以舊換新服務;