本次案例的數據來源于CDNOW待诅,是美國的一家網上唱片公司,數據描述的是這家公司網站上的用戶消費記錄熊镣,分析目標旨在分析用戶消費行為卑雁,建立RFM模型,分析復購率绪囱、回購率等關鍵指標测蹲。數據字典如下:
- user_id:用戶ID
- order_dt:購買日期
- order_products:購買產品數
- order_amount:購買金額
數據集包含69659條記錄,共有4個字段鬼吵,時間范圍從19970101-19980630之間扣甲,下面是數據集整理統計描述:
一、用戶消費趨勢分析(按月)
分別統計每月的消費總金額而柑、消費次數文捶、產品購買量、消費人數
grouped_month_info = grouped_month[['order_amount','user_id','order_products']].agg({'order_amount':sum, 'user_id': 'count', 'order_products':sum}).reset_index()
grouped_month_info.rename(columns = {'order_amount':'消費金額', 'user_id': '消費次數', 'order_products': '產品購買量'}, inplace=True)
grouped_month['user_id'].unique().map(len)
grouped_month_info['消費人次'] = grouped_month['user_id'].unique().map(len)
由上圖可知媒咳,消費金額在前三個月達到最高峰粹排,后續(xù)消費較為穩(wěn)定,有輕微下降趨勢
由上圖可知涩澡,產品購買量在前三個月達到最高峰顽耳,后續(xù)消費較為穩(wěn)定,有輕微下降趨勢
前三個月消費訂單人數在10000筆左右,后續(xù)月份的平均消費人數則在2500人射富,每月消費人數低于每月消費次數膝迎,但差異不大。
二胰耗、用戶個體消費分析
1限次、用戶消費金額,消費次數的描述統計
grouped_user=df.groupby('user_id').sum().describe()
out:
order_products order_amount
count 23570.000000 23570.000000
mean 7.122656 106.080426
std 16.983531 240.925195
min 1.000000 0.000000
25% 1.000000 19.970000
50% 3.000000 43.395000
75% 7.000000 106.475000
max 1033.000000 13990.930000
結果如下:
用戶平均購買了7張柴灯,但是中位值只有3卖漫,說明小部分用戶購買了大量貨物,用戶平均消費106元赠群,中位值有43羊始,判斷同上,這說明也有極值干擾查描。
2突委、用戶消費金額和消費次數的散點圖
為排除極值干擾冬三,order_amount篩選<4000,由散點圖可知匀油,用戶消費金額與產品購買量幾乎成線性關系,購買的商品越多勾笆,消費金額就越大钧唐。
3、用戶消費金額和頻次的分布圖
grouped_user_sum_order_amount = grouped_user.sum().order_amount #每個用戶的金額
grouped_user_sum_order_amount_lst = [i for i in range(0,int(grouped_user_sum_order_amount.max())+50,50)]
grouped_user_sum_order_amount = pd.cut(grouped_user_sum_order_amount, bins=grouped_user_sum_order_amount_lst,labels = grouped_user_sum_order_amount_lst[1:])
從直方圖可知匠襟,用戶消費金額,絕大部分呈現集中趨勢该园,小部分異常值干擾了判斷酸舍,可以使用過濾操作排除異常, 這里我們使用切比雪夫定理過濾掉異常值,因為切比雪夫定理說明里初,95%的數據都分布在5個標準差之內啃勉,剩下5%的極值就不要了。如下:
order_amount (mean = 106 ,std = 241) mean+5std = 1311
4双妨、用戶累計消費金額占比(百分之多少的用戶占了百分之多少的消費額)
# cumsum 是求累加值
user_cumsum=grouped_user.sum().sort_values('order_amount').apply(lambda x:x.cumsum()/x.sum())
按照用戶消費金額進行升序排序淮阐,由圖可以知道50%的用戶僅貢獻了11%的消費額度,而排名前5000的用戶就貢獻了60%的消費額度刁品。
三泣特、用戶消費行為
1、用戶第一次消費(首購)
grouped_user_min = grouped_user.min().order_dt.value_counts().reset_index().rename(columns={'index':'first_date'})
grouped_user_min['first_date'] =grouped_user_min['first_date'].astype(str)
用戶第一次購買分布集中在前三個月挑随。其中状您,在2月9日到2月25日之間有劇烈的波動。
2、用戶最后一次消費
grouped_user_max = grouped_user.max().order_dt.value_counts().reset_index().rename(columns={'index':'last_date'})
grouped_user_max['last_date'] =grouped_user_max['last_date'].astype(str)
上圖呈現斷崖式下跌很正常膏孟,可以理解為用戶流失比例基本一致眯分,一開始用戶迅猛增長數量比較多流失的也比較多,后面沒有用戶柒桑,用戶最后一次購買的分布比第一次分布廣弊决,大部分最后一次購買,集中在前三個月魁淳,說明很多用戶購買了一次后就不再進行購買飘诗。隨著時間的遞增,最后一次購買數量也在遞增先改,消費呈現流失上升的狀況(這也是正常疚察,隨著時間的增長,可能因為運營沒有跟上或者用戶忠誠度下降了)
3仇奶、新老客戶消費比
- 多少用戶僅消費一次
#新老客消費比
# 得到第一次和最后yc次消費情況貌嫡,如果 min、max 日期相同该溯,說明只消費了一次
user_life=grouped_user.order_dt.agg(['min','max'])
# 統計只消費了一次的用戶
(user_life['min']==user_life['max']).value_counts()
結論得出大概有一半的用戶岛抄,只消費了一次
- 每月新客占比
# 按照month、userid分組狈茉,第一次和最后一次消費日期
user_life_month=df.groupby(['month','user_id']).order_dt.agg(['min','max']).reset_index()
# 新增is_new字段夫椭,用于標記新用戶
user_life_month['is_new']=(user_life_month['min']==user_life_month['max'])
# 再次按month分組,計算新用戶占比
user_life_month_pct=user_life_month.groupby('month').is_new.apply(lambda x:x.value_counts()/x.count()).reset_index()
# level_1為True的作圖
user_life_month_pct[user_life_month_pct.level_1].plot(x='month',y='is_new')
上圖看出1997年1月新用戶占比高達90%以上氯庆,后續(xù)有所下降蹭秋,并逐漸趨于平穩(wěn),1997年4月到1998年6月維持在81%左右堤撵,1998年6月以后無新用戶仁讨。
4、用戶分層
- RFM模型
R:最后一次消費距今天數实昨,F:消費總金額 洞豁,M:消費總產品數
為得到最近一次消費,一般是計算 today 距離最近一次消費荒给,這里因為時間太久遠丈挟,就隨便用的max值,數值越大就越久遠志电,分子得到的是一些天數類似 545 days(因為是時間格式相減)曙咽,再除以一個單位,就不會有單位了溪北,只留下數值桐绒,如下:
# 重命名夺脾,也就是 R:最后一次消費距今天數
rfm['R']= -(rfm.order_dt - rfm.order_dt.max())/np.timedelta64(1,'D')
# F:消費金額 M:消費頻次
rfm.rename(columns={'order_products':"F",'order_amount':'M'},inplace=True)
# RFM模型
def rfm_func(x):
level=x.apply(lambda x:'1' if x>=0 else '0')
# level 的類型是 series,index 是 R茉继、F咧叭、M
#print(level)
#print(level.index)
label=level.R + level.F + level.M
#print(label)
d={
# R 為1 表示離均值較遠即時間很久,F為1 表示 消費金額比較多烁竭,M 為1 表示消費頻次比較多菲茬,所以是重要價值客戶
'111':'重要價值客戶',
'011':'重要保持客戶',
'101':'重要發(fā)展客戶',
'001':'重要挽留客戶',
'110':'一般價值客戶',
'010':'一般保持客戶',
'100':'一般發(fā)展客戶',
'000':'一般挽留客戶',
}
result=d[label]
return result
# 注意這里是要一行行的傳遞進來,所以 axis=1派撕,傳遞一行得到一個 111婉弹,然后匹配返回一個值
rfm['label']=rfm[['R','F','M']].apply(lambda x:x-x.mean()).apply(rfm_func,axis=1)
# 歸結為兩類方便得出客戶標簽
rfm.loc[rfm.label=='重要價值客戶','color']='重要價值客戶'
rfm.loc[~(rfm.label=='重要價值客戶'),'color']='非重要價值客戶'
紫色部分是重要價值客戶,消費頻次較高终吼。
rfm.groupby('label').sum()
M F R
label
一般價值客戶 7181.28 650 36295.0
一般保持客戶 19937.45 1712 29448.0
一般發(fā)展客戶 438291.81 29346 6951815.0
一般挽留客戶 196971.23 13977 591108.0
重要價值客戶 167080.83 11121 358363.0
重要保持客戶 1592039.62 107789 517267.0
重要發(fā)展客戶 33028.40 1263 114482.0
重要挽留客戶 45785.01 2023 56636.0
從RFM 分層可知镀赌,大部分用戶是重要保持客戶,但是這是由于極值的影響际跪,所以 RFM 的劃分標準應該以業(yè)務為準商佛,也可以通過切比雪夫去除極值后求均值,并且 RFM 的各個劃分標準可以都不一樣.
- 新姆打、老良姆、活躍、回流幔戏、流失
# 數據透視玛追, userid為索引,月為列闲延,求每月的消費次數痊剖,這里填充了
pivoted_counts=df.pivot_table(index='user_id',
columns='month',
values='order_dt',
aggfunc='count').fillna(0)
# 轉變一下消費,有消費為1垒玲,沒有消費為0
df_purchase=pivoted_counts.applymap(lambda x:1 if x>0 else 0)
df_purchase.tail()
# 這里由于進行數據透視邢笙,填充了一些 null 值為0,而實際可能用戶在當月根本就沒有注冊侍匙,
#這樣會誤導第一次消費數據的統計,所以寫一個函數來處理
# 上面填充了一些null值為0叮雳,而實際可能用戶在當月根本就沒有注冊想暗,這樣會誤導第一次消費數據的統計,所以寫一個函數來處理
def active_status(data):
status=[]
# 數據一共有18個月份帘不,每次輸入一行數據说莫,也就是一個user_id的信息,進行逐月判斷
for i in range(18):
# 若本月沒有消費
if data[i]==0:
# 判斷之前有沒有數據寞焙,之前有數據
if len(status)>0:
# 判斷上個月是否為未注冊(如果上個月未注冊储狭,本月沒有消費互婿,仍為未注冊)
if status[i-1]=='unreg':
status.append('unreg')
# 上月有消費,本月沒有消費辽狈,則為不活躍
else:
status.append('unactive')
# 之前一個數據都沒有慈参,就認為是未注冊
else:
status.append('unreg')
# 若本月消費
else:
# 之前無記錄,本月是第一次消費刮萌,則為新用戶
if len(status)==0:
status.append('new')
# 之前有記錄
else:
# 上個月是不活躍驮配,這個月消費了,則為回流用戶
if status[i-1]=='unactive':
status.append('return')
# 上個月未注冊着茸,這個月消費了壮锻,則為新用戶
elif status[i-1]=='unreg':
status.append('new')
# 上個月消費了,本月仍消費涮阔,則為活躍用戶
else:
status.append('active')
return status
關于active_status的說明:
return:回流 new:新客 unreg:未注冊 active:活躍
若本月沒有消費猜绣,這里只是和上個月判斷是否注冊,有一定的缺陷敬特,應該判斷是否存在就可以了
若之前有數據掰邢,是未注冊,則依舊為未注冊
若之前有數據擅羞,不是未注冊尸变,則為流失/不活躍
若之前沒有數據,為未注冊
若本月有消費
若是第一次消費减俏,則為新用戶
若之前有過消費召烂,上個月為不活躍,則為回流
若之前有過消費娃承,上個月為未注冊奏夫,則為新用戶
若之前有過消費,其他情況為活躍
purchase_stats=df_purchase.apply(lambda x: pd.Series(active_status(x),index=df_purchase.columns),axis=1)
purchase_stats.head()
# 這里把未注冊的替換為空值历筝,這樣 count 計算時不會計算到
# 得到每個月的用戶分布
purchase_stats_ct=purchase_stats.replace('unreg',np.NaN).apply(lambda x:pd.value_counts(x))
purchase_stats_ct
returnratee=purchase_stats_ct.apply(lambda x:x/x.sum(),axis=0)
purchase_stats_ct_info = purchase_stats_ct.fillna(0).T
前三個月有大量新用戶涌入酗昼,新用戶占比很高,而后面幾個月不活躍用戶占比非常高梳猪,普遍在90%以上麻削。活躍用戶春弥,持續(xù)消費的用戶呛哟,對應的是消費運營的質量∧渑妫回流用戶扫责,之前不消費,本月才消費逃呼,對應的是喚回運營鳖孤。不活躍用戶者娱,對應的是流失。
5苏揣、用戶購買周期(按訂單)
- 用戶消費周期描述
# 用戶購買周期(按訂單)
# 計算相鄰兩個訂單的時間間隔黄鳍,shift 函數是對數據進行錯位,所有數據會往下平移一下腿准,所以可以
order_diff=grouped_user.apply(lambda x:x.order_dt-x.order_dt.shift())
order_diff.head(10)
描述性統計:
- 用戶消費周期分布
![用戶消費周期分布].png](https://upload-images.jianshu.io/upload_images/7169608-1daba0a49d01c614.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
訂單周期呈指數分布际起,用戶的平均購買周期是68天,最小值0天吐葱,最大值533天街望,絕大部分用戶的購買周期都低于100天。
6弟跑、用戶生命周期(按第一次和最后一次消費)
-
用戶生命周期描述
-
用戶生命周期分布
用戶平均生命周期134天灾前,但中位數僅0天。用戶的生命周期分布受只購買一次的用戶(用戶生命周期0天)影響比較嚴重孟辑,可以排除哎甲,得到:
用戶平均生命周期276天,中位數302天饲嗽。
7炭玫、復購率
復購率:自然月內,購買多次的用戶占比(即貌虾,購買了兩次以上)
# 區(qū)分一個吞加,和一個以上的情況,以便于計算復購率尽狠,大于1為1衔憨,等于0 為NaN,等于1為0
purchase_r=pivoted_counts.applymap(lambda x: 1 if x>1 else np.NaN if x==0 else 0)
purchase_r.head()
purchase_r_reshop = (purchase_r.sum()/purchase_r.count()).reset_index(name = 'reshop')
復購率穩(wěn)定在20%所有袄膏,前一個月因為有大量新用戶涌入践图,而這批用戶只購買了一次,所以導致復購率降低
8沉馆、回購率
回購率:曾經購買過的用戶在某一時期的再次購買的占比(可能是在三個月內)
# 需要使用函數來判斷是否回購:當月消費過的用戶下個月也消費了叫做回購码党,這個定義可以改變
def purchase_back(data):
# 判斷每一個月是否是回購,根據下個月是否購買來判斷
status=[]
for i in range(17):
# 本月消費
if data[i]==1:
# 下個月回購
if data[i+1]==1:
status.append(1)
# 下個月沒回購
if data[i+1]==0:
status.append(0)
# 本月沒消費斥黑,賦予空值闽瓢,不參與計算
else:
status.append(np.NaN)
# 第18個月補充NaN,因為沒有下個月的數據了
status.append(np.NaN)
return status
indexs=df['month'].sort_values().astype('str').unique()
purchase_b = df_purchase.apply(lambda x :pd.Series(purchase_back(x),index = indexs),axis =1)
# 回購率心赶,回購的次數/總購買次數
purchase_b_backshop = purchase_b.sum()/purchase_b.count()
回購率穩(wěn)定在30%左右,前3個月因為有大量新用戶涌入缺猛,而這批用戶只購買了一次缨叫,所以導致回購率較低椭符。
四、小結
1耻姥、用戶消費趨勢(每月)方面销钝,前3個月有大量新用戶涌入,消費金額琐簇、消費訂單數蒸健、產品購買量均達到高峰,后續(xù)每月較為穩(wěn)定婉商。前3個月消費次數都在10000筆左右似忧,后續(xù)月份的平均2500;前3個月產品購買量達到20000甚至以上丈秩,后續(xù)月份平均7000盯捌;前3個月消費人數在8000-10000之間,后續(xù)月份平均2000不到蘑秽。
2饺著、用戶個體消費方面大概符合二八法則,小部分用戶購買了大量的CD肠牲,拉高了平均消費金額幼衰。用戶消費金額集中在0100元,有大約17000名用戶缀雳。用戶購買量集中在05個渡嚣,有大約16000名用戶。50%的用戶僅貢獻了15%的消費額度俏险,15%的用戶貢獻了60%的消費額度严拒。
3、用戶消費行為方面竖独,首購和最后一次購買的時間裤唠,集中在前三個月,說明很多用戶購買了一次后就不再進行購買莹痢。而且最后一次購買的用戶數量也在隨時間遞增种蘸,消費呈現流失上升的狀況。
4竞膳、從整體消費記錄來看航瞭,有一半的用戶,只消費了一次坦辟。從每月新用戶占比來看刊侯,1997年1月新用戶占比高達90%以上,后續(xù)有所下降锉走,1997年4月到1998年6月維持在81%左右滨彻,1998年6月以后無新用戶藕届。
5、從RFM模型來看亭饵,在8種客戶中休偶,重要保持客戶的消費頻次和消費金額最高,人數排在第二位辜羊;而一般發(fā)展客戶消費頻次和消費金額排第二位踏兜,人數卻是最多。
6八秃、從用戶分層情況來看帜慢,新用戶從第4月份以后沒有新增笙蒙;活躍用戶有所下降涌攻;回流用戶數量趨于穩(wěn)定墙歪,每月1000多。流失/不活躍用戶舍悯,數量非常多航棱,基本上每月都在20000以上。
7萌衬、用戶購買周期方面饮醇,平均購買周期是68天,最小值0天秕豫,最大值533天朴艰。絕大部分用戶的購買周期都低于100天。
8混移、用戶生命周期方面祠墅,由于只購買一次的用戶(生命周期為0天)占了接近一半,排除這部分用戶的影響之后歌径,用戶平均生命周期276天毁嗦,中位數302天。
9回铛、復購率和回購率方面狗准,復購率穩(wěn)定在20%左右,回購率穩(wěn)定在30%左右茵肃,前3個月因為有大量新用戶涌入腔长,而這批用戶只購買了一次,所以導致復購率和回購率都比較低验残。