一汇跨、項(xiàng)目背景
CDNow是美國(guó)的一家網(wǎng)上唱片公司,成立于1994年虑乖,后來(lái)被貝塔斯曼音樂集團(tuán)收購(gòu)。為了平臺(tái)創(chuàng)造出更多的利潤(rùn),并且能夠合理的投放廣告晾虑,現(xiàn)使用網(wǎng)站1997年1月至1998年6月期間的用戶消費(fèi)數(shù)據(jù)進(jìn)行分析疹味。
二、分析目標(biāo)
通過對(duì)該CD網(wǎng)站上的用戶消費(fèi)數(shù)據(jù)進(jìn)行分析帜篇,得出用戶消費(fèi)行為佛猛,建立RFM模型,分析復(fù)購(gòu)率坠狡、回購(gòu)率等關(guān)鍵指標(biāo)結(jié)果继找,以便更清楚了解用戶,為進(jìn)一步的營(yíng)銷策略提供依據(jù)逃沿。
三婴渡、分析框架
數(shù)據(jù)清洗
- 數(shù)據(jù)加載
- 數(shù)據(jù)觀察與清洗
用戶消費(fèi)趨勢(shì)分析(按月)
- 月產(chǎn)品銷售額
- 月產(chǎn)品銷售量
- 月消費(fèi)次數(shù) 與 月消費(fèi)人數(shù)
- 每月用戶平均消費(fèi)金額趨勢(shì)
- 每月用戶平均消費(fèi)次數(shù)趨勢(shì)
用戶個(gè)體消費(fèi)分析
- 用戶消費(fèi)金額與商品購(gòu)買量的描述統(tǒng)計(jì)
- 用戶消費(fèi)金額和商品購(gòu)買量散點(diǎn)圖
- 用戶消費(fèi)分布圖
- 用戶累計(jì)消費(fèi)金額占比
用戶消費(fèi)行為分析
- 用戶第一次消費(fèi)(首購(gòu))
- 用戶最后一次消費(fèi)
- 新老客戶消費(fèi)比(多少用戶僅消費(fèi)一次,每月新用戶占比)
- 用戶分層(RFM模型凯亮,新边臼、老、活躍假消、回流柠并、流失,回流用戶占比)
- 用戶消費(fèi)周期(按訂單)(用戶消費(fèi)周期描述富拗,用戶消費(fèi)周期分布)
- 用戶生命周期(用戶生命周期描述臼予,用戶生命周期分布)
復(fù)購(gòu)率和回購(gòu)率分析
- 復(fù)購(gòu)率
- 回購(gòu)率
留存率分析
四、數(shù)據(jù)清洗
# 導(dǎo)入常用包
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 加載可視化數(shù)據(jù)包
%matplotlib inline # 可視化顯示在頁(yè)面啃沪,%代表內(nèi)置命令粘拾,inline 顯示圖標(biāo)
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用來(lái)正常顯示中文標(biāo)簽
plt.rcParams['axes.unicode_minus'] = False # 用來(lái)正常顯示負(fù)號(hào)
plt.style.use('ggplot') # 更改設(shè)計(jì)風(fēng)格,使用 ggplot style 繪圖
1.數(shù)據(jù)加載
# 加載數(shù)據(jù)
columns = ['user_id','order_dt','order_products','order_amount']
df = pd.read_table('CDNow_master.txt',names = columns, sep = '\s+') # s+ 自動(dòng)處理多個(gè)空格
本數(shù)據(jù)集為 CDNow 網(wǎng)站 1997年1月至1998年6月的用戶行為數(shù)據(jù)创千,共約 7 萬(wàn)行缰雇,4 列,分別是:
- user_id:用戶ID
- order_dt:購(gòu)買日期
- order_products:購(gòu)買產(chǎn)品數(shù)
- order_amount:購(gòu)買金額
2.數(shù)據(jù)觀察與清洗
print(df.info())
print('-'*60)
print(df.isnull().sum())
print('-'*60)
print(df.head())
print('-'*60)
print(df.tail())
print('-'*60)
print(df.describe())
Out:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 69659 entries, 0 to 69658
Data columns (total 4 columns):
user_id 69659 non-null int64
order_dt 69659 non-null int64
order_products 69659 non-null int64
order_amount 69659 non-null float64
dtypes: float64(1), int64(3)
memory usage: 2.1 MB
None
------------------------------------------------------------
user_id 0
order_dt 0
order_products 0
order_amount 0
dtype: int64
------------------------------------------------------------
user_id order_dt order_products order_amount
0 1 19970101 1 11.77
1 2 19970112 1 12.00
2 2 19970112 5 77.00
3 3 19970102 2 20.76
4 3 19970330 2 20.76
------------------------------------------------------------
user_id order_dt order_products order_amount
69654 23568 19970405 4 83.74
69655 23568 19970422 1 14.99
69656 23569 19970325 2 25.74
69657 23570 19970325 3 51.12
69658 23570 19970326 2 42.96
------------------------------------------------------------
user_id order_dt order_products order_amount
count 69659.000000 6.965900e+04 69659.000000 69659.000000
mean 11470.854592 1.997228e+07 2.410040 35.893648
std 6819.904848 3.837735e+03 2.333924 36.281942
min 1.000000 1.997010e+07 1.000000 0.000000
25% 5506.000000 1.997022e+07 1.000000 14.490000
50% 11410.000000 1.997042e+07 2.000000 25.980000
75% 17273.000000 1.997111e+07 3.000000 43.700000
max 23570.000000 1.998063e+07 99.000000 1286.010000
結(jié)果顯示:
- 數(shù)據(jù)集不存在缺失值;
- 后續(xù)需要對(duì) order_dt 列進(jìn)行分析計(jì)算,需要將數(shù)據(jù)類型 int64 轉(zhuǎn)換為日期型 datetime64[ns]剩彬;
- 后續(xù)需要按月分析杆故,所以將日期進(jìn)行解析(實(shí)際業(yè)務(wù)是否按月分析,取決于消費(fèi)頻率);
- 用戶平均商品購(gòu)買量較少,為 2.4梗摇,有一定極值干擾糯崎;
- 用戶消費(fèi)金額比較穩(wěn)定, 平均值為 35 美元, 中位數(shù)為 25 美元, 有一定極值干擾几缭;
- 數(shù)據(jù)呈右偏分布。
# 解析時(shí)間
df['order_dt'] = pd.to_datetime(df.order_dt,format="%Y%m%d") # 數(shù)據(jù)類型int64轉(zhuǎn)換為datetime64[ns]沃呢,ns 代表時(shí)間間隔
df['month'] = df.order_dt.values.astype('datetime64[M]') # 添加新列 month年栓,對(duì)order_dt列(取values),轉(zhuǎn)換類型為datetime64[M]薄霜,默認(rèn)是每月的第1天某抓,同理設(shè)置為[Y]就是每年的1月1日
3.用戶消費(fèi)趨勢(shì)分析(按月)
# 按月分組
grouped_month = df.groupby('month')
3.1 月產(chǎn)品銷售額
# 月產(chǎn)品銷售額
grouped_month.order_amount.sum()
grouped_month.order_amount.sum().head()
Out:
month
1997-01-01 299060.17
1997-02-01 379590.03
1997-03-01 393155.27
1997-04-01 142824.49
1997-05-01 107933.30
Name: order_amount, dtype: float64
# 折線圖繪制
plt.figure(1,figsize = (10,4)) # 創(chuàng)建畫板
plt.title('月產(chǎn)品銷售額')
plt.ylabel('銷售額/美元')
grouped_month.order_amount.sum().plot() # plot - 折線圖
結(jié)果顯示:
- 銷售額在前3個(gè)月持續(xù)增長(zhǎng),在第3個(gè)月達(dá)到最高峰惰瓜,后續(xù)消費(fèi)較為穩(wěn)定否副,有輕微下降趨勢(shì)。
3.2 月產(chǎn)品銷售量
# 月產(chǎn)品銷售量
grouped_month.order_products.sum()
grouped_month.order_products.sum().head()
Out:
month
1997-01-01 19416
1997-02-01 24921
1997-03-01 26159
1997-04-01 9729
1997-05-01 7275
Name: order_products, dtype: int64
# 折線圖繪制
plt.figure(1,figsize = (10,4))
plt.title('月產(chǎn)品銷售量')
plt.ylabel('銷售量/張')
grouped_month.order_products.sum().plot()
結(jié)果顯示:
- 銷量在前3個(gè)月持續(xù)增長(zhǎng)崎坊,并在3月達(dá)到最高峰备禀,后續(xù)銷量較為穩(wěn)定,且有輕微下降趨勢(shì)奈揍。
3.3 月消費(fèi)次數(shù) 與 月消費(fèi)人數(shù)
# 月消費(fèi)次數(shù)
grouped_month.user_id.count()
grouped_month.user_id.count().head()
Out:
month
1997-01-01 8928
1997-02-01 11272
1997-03-01 11598
1997-04-01 3781
1997-05-01 2895
Name: user_id, dtype: int64
# 月消費(fèi)人數(shù)
grouped_month['user_id'].unique().map(len) #使用map 和len 函數(shù)去重計(jì)算
# grouped_month.user_id.apply(lambda x: len(x.drop_duplicates())) #重復(fù)值處理函數(shù)drop_duplicates
grouped_month['user_id'].unique().map(len).head()
Out:
month
1997-01-01 7846
1997-02-01 9633
1997-03-01 9524
1997-04-01 2822
1997-05-01 2214
Name: user_id, dtype: int64
# 折線圖繪制
plt.figure(1, figsize = (10, 4))
plt.title('月消費(fèi)次數(shù) 與 月消費(fèi)人數(shù)')
plt.ylabel('次數(shù)/人數(shù)')
grouped_month.user_id.count().plot(label = '次數(shù)')
grouped_month['user_id'].unique().map(len).plot(label = '人數(shù)')
plt.legend() # 給圖像加上圖例
結(jié)果顯示:
- 每月消費(fèi)人數(shù)低于每月消費(fèi)次數(shù)曲尸,但差異不大;
- 前3個(gè)月每月的消費(fèi)人數(shù)在8000-10000之間男翰,后續(xù)月份的平均消費(fèi)人數(shù)穩(wěn)定在2000左右另患。
# 以上匯總分析,可以用數(shù)據(jù)透視的方法更快實(shí)現(xiàn)蛾绎,但數(shù)據(jù)透視表進(jìn)行去重操作比較麻煩昆箕,不建議使用
pivot_df = df.pivot_table(index = 'month',
values = ['order_products','order_amount','user_id'],
aggfunc = {'order_products':'sum','order_amount':'sum','user_id':'count'})
pivot_df.head()
Out:
order_amount order_products user_id
month
1997-01-01 299060.17 19416 8928
1997-02-01 379590.03 24921 11272
1997-03-01 393155.27 26159 11598
1997-04-01 142824.49 9729 3781
1997-05-01 107933.30 7275 2895
# 數(shù)據(jù)透視表繪制
pivot_df.plot(figsize = (10, 4))
3.4 每月用戶平均消費(fèi)金額趨勢(shì)
# 每月用戶平均消費(fèi)金額 = 月產(chǎn)品銷售額 / 月消費(fèi)人數(shù)
amount = grouped_month.order_amount.sum()
num = grouped_month['user_id'].unique().map(len)
avg_amount = amount/num
avg_amount.head()
Out:
month
1997-01-01 38.116259
1997-02-01 39.405173
1997-03-01 41.280478
1997-04-01 50.611088
1997-05-01 48.750361
dtype: float64
# 折線圖繪制
plt.figure(1, figsize = (10, 4))
plt.title('每月用戶平均消費(fèi)金額趨勢(shì)')
plt.ylabel('金額/美元')
avg_amount.plot()
結(jié)果顯示:
- 每月用戶平均消費(fèi)金額在1月最低,約38美元租冠,11月達(dá)到最高鹏倘,約57美元。
3.5 每月用戶平均消費(fèi)次數(shù)趨勢(shì)
# 每月用戶平均消費(fèi)次數(shù)趨勢(shì) = 月消費(fèi)次數(shù) / 月消費(fèi)人數(shù)
times = grouped_month.user_id.count()
num = grouped_month['user_id'].unique().map(len)
avg_times = times/num
avg_times.head()
Out:
month
1997-01-01 1.137905
1997-02-01 1.170144
1997-03-01 1.217766
1997-04-01 1.339830
1997-05-01 1.307588
Name: user_id, dtype: float64
# 折線圖繪制
plt.figure(1, figsize = (10, 4))
plt.title('每月用戶平均消費(fèi)次數(shù)趨勢(shì)圖')
plt.ylabel('消費(fèi)次數(shù)/次')
avg_times.plot()
結(jié)果顯示:
- 每月用戶平均消費(fèi)次數(shù)均在1次以上肺稀,1月份最低第股,約為1.1次,10月份最高话原,約為1.4次。
4.用戶個(gè)體消費(fèi)分析
# 按用戶分組
grouped_user = df.groupby('user_id')
4.1 用戶消費(fèi)金額與商品購(gòu)買量的描述統(tǒng)計(jì)
# 用戶消費(fèi)金額與商品購(gòu)買量的描述統(tǒng)計(jì)
grouped_user.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
結(jié)果顯示:
- 用戶總購(gòu)買量為 23570 張诲锹,平均每位用戶購(gòu)買 7 張繁仁,中位數(shù)為 3 張,平均數(shù)大于中位數(shù)归园,呈右偏分布黄虱,說(shuō)明小部分用戶購(gòu)買了大部分的CD。
- 用戶平均消費(fèi) 106 美元庸诱,中位數(shù)為 43 美元捻浦,高頻消費(fèi)用戶集中在小部分用戶中晤揣,存在極值干擾。
4.2 用戶消費(fèi)金額和商品購(gòu)買量散點(diǎn)圖
# 圖形繪制
plt.figure(figsize = (12,4))
# 用戶消費(fèi)金額散點(diǎn)圖
plt.subplot(121)
plt.scatter(x = 'order_amount', y = 'order_products',data=df)
plt.xlabel('每筆訂單消費(fèi)金額')
plt.ylabel('每筆訂單購(gòu)買數(shù)量')
# 用戶購(gòu)買數(shù)量散點(diǎn)圖
plt.subplot(122)
plt.scatter(x = 'order_amount',y = 'order_products',data = grouped_user.sum())
plt.xlabel('每位用戶消費(fèi)金額')
plt.ylabel('每位用戶購(gòu)買數(shù)量')
結(jié)果顯示:
- 絕大部分的數(shù)據(jù)集中分布朱灿,小部分極值對(duì)分析有一定的干擾昧识,使用query函數(shù)對(duì)order_amount進(jìn)行篩選,排除極值的干擾盗扒。
# 散點(diǎn)圖繪制
plt.figure(figsize = (12,4))
# 用戶消費(fèi)金額散點(diǎn)圖
plt.subplot(121)
plt.scatter(x = 'order_amount', y = 'order_products',data = df.query('order_amount<800'))
plt.xlabel('每筆訂單消費(fèi)金額')
plt.ylabel('每筆訂單購(gòu)買數(shù)量')
# 用戶購(gòu)買數(shù)量散點(diǎn)圖
plt.subplot(122)
plt.scatter(x = 'order_amount',y = 'order_products',data = grouped_user.sum().query('order_amount<4000'))
plt.xlabel('每位用戶消費(fèi)金額')
plt.ylabel('每位用戶購(gòu)買數(shù)量')
結(jié)果顯示:
- 用戶消費(fèi)金額與產(chǎn)品購(gòu)買量基本呈線性分布跪楞,產(chǎn)品購(gòu)買越多,消費(fèi)金額越高侣灶。
4.3 用戶消費(fèi)分布圖
為過濾異常值甸祭,這里以order_amount 和order_product為過濾條件,使用切比雪夫定理過濾掉4%的極值褥影。
切比雪夫定理
任意一個(gè)數(shù)據(jù)集中池户,位于其平均數(shù)m個(gè)標(biāo)準(zhǔn)差范圍內(nèi)的比例(或部分)總是至少為1-1/m2,其中m為大于1的任意正數(shù)凡怎。對(duì)于m=2校焦,m=3和m=5有如下結(jié)果:
- 所有數(shù)據(jù)中,至少有3/4(或75%)的數(shù)據(jù)位于平均數(shù)2個(gè)標(biāo)準(zhǔn)差范圍內(nèi)栅贴。
- 所有數(shù)據(jù)中斟湃,至少有8/9(或88.9%)的數(shù)據(jù)位于平均數(shù)3個(gè)標(biāo)準(zhǔn)差范圍內(nèi)。
- 所有數(shù)據(jù)中檐薯,至少有24/25(或96%)的數(shù)據(jù)位于平均數(shù)5個(gè)標(biāo)準(zhǔn)差范圍內(nèi)
# 直方圖繪制
plt.figure(figsize=(12, 4))
plt.subplot(121)
ax1 = grouped_user.order_amount.sum().hist(bins = 100) # bins是分組
ax1.set_xlabel('金額/美元')
ax1.set_ylabel('人數(shù)/人')
# order_amount (mean = 106 ,std = 241) mean+5std = 1311
ax1.set_xlim(0, 1400)
ax1.set_title('用戶消費(fèi)金額分布')
plt.subplot(122)
ax2 = grouped_user.order_products.sum().hist(bins = 100)
ax2.set_xlabel('CD 數(shù)/張')
ax2.set_ylabel('人數(shù)/人')
# order_product (mean = 7 ,std = 17) mean+5std = 92
ax2.set_xlim(0, 100)
ax2.set_title('用戶購(gòu)買數(shù)量分布')
結(jié)果顯示:
- 用戶消費(fèi)金額呈現(xiàn)集中分布凝赛,大部分用戶消費(fèi)在200美元以內(nèi);
- 用戶購(gòu)買數(shù)量呈現(xiàn)集中分布坛缕,大部分用戶購(gòu)買CD數(shù)少于20張墓猎。
4.4 用戶累計(jì)消費(fèi)金額占比
# cumsum 求累加值,按照用戶消費(fèi)金額進(jìn)行升序排序
user_cumsum = grouped_user.sum().sort_values('order_amount').apply(lambda x:x.cumsum() / x.sum())
# reset_index() 是為了得到一個(gè)自然數(shù)的行標(biāo)簽赚楚,表示累計(jì)用戶數(shù)量
user_cumsum.reset_index().order_amount.tail()
Out:
23565 0.985405
23566 0.988025
23567 0.990814
23568 0.994404
23569 1.000000
Name: order_amount, dtype: float64
# 曲線圖繪制
plt.figure(figsize=(10, 4))
user_cumsum.reset_index().order_amount.plot()
plt.title('用戶累計(jì)消費(fèi)金額占比')
plt.xlabel('人數(shù)/人')
plt.ylabel('百分比/%')
plt.axhline(y = 0.8,ls = "--",c = "blue",lw = 1) # 添加水平直線
plt.axvline(x = len(df.user_id.unique())*0.8,ls = "--",c = "green",lw = 1) # 添加垂直直線
結(jié)果顯示:
- 按照用戶消費(fèi)金額進(jìn)行升序排序毙沾,50%的用戶僅貢獻(xiàn)了11%的消費(fèi)額度,而排名前5000的用戶就貢獻(xiàn)了60%的銷售額宠页,基本符合二八定律左胞。
5.用戶消費(fèi)行為分析
5.1 用戶第一次消費(fèi)(首購(gòu))
# 首次購(gòu)買即日期最小值
grouped_user.min().order_dt.value_counts() # value_counts()計(jì)數(shù)函數(shù)
grouped_user.min().order_dt.value_counts().head()
Out:
1997-02-08 363
1997-02-24 347
1997-02-04 346
1997-02-06 346
1997-03-04 340
Name: order_dt, dtype: int64
# 折線圖繪制
plt.figure(figsize=(10, 4))
plt.title('用戶第一次購(gòu)買時(shí)間分布')
plt.xlabel('人數(shù)/人')
plt.ylabel('百分比/%')
grouped_user.min().order_dt.value_counts().plot()
結(jié)果顯示:
- 用戶第一次購(gòu)買的時(shí)間集中分布在前3個(gè)月,其中在02月11日 - 02月25日期間有一次劇烈波動(dòng)举户。
5.2 用戶最后一次消費(fèi)
# 對(duì)最大日期進(jìn)行計(jì)數(shù)
grouped_user.month.max().value_counts()
grouped_user.month.max().value_counts().head()
Out:
1997-02-01 4912
1997-03-01 4478
1997-01-01 4192
1998-06-01 1506
1998-05-01 1042
Name: month, dtype: int64
# 折線圖繪制
plt.figure(figsize=(10, 4))
plt.title('用戶最后一次購(gòu)買時(shí)間分布')
plt.xlabel('人數(shù)/人')
plt.ylabel('百分比/%')
grouped_user.max().order_dt.value_counts().plot()
結(jié)果顯示:
- 用戶最后一次購(gòu)買的時(shí)間分布范圍較廣烤宙,大部分用戶的最后一次購(gòu)買時(shí)間集中在前3個(gè)月,說(shuō)明這部分用戶只購(gòu)買了一次俭嘁,忠實(shí)用戶較少躺枕。
5.3 新老用戶消費(fèi)比
# 得到第一次和最后一次消費(fèi)情況
user_life = grouped_user.order_dt.agg(['min','max'])
user_life.head()
Out:
min max
user_id
1 1997-01-01 1997-01-01
2 1997-01-12 1997-01-12
3 1997-01-02 1998-05-28
4 1997-01-01 1997-12-12
5 1997-01-01 1998-01-03
a. 多少用戶僅消費(fèi)一次
# 統(tǒng)計(jì)只消費(fèi)了一次的用戶,如果 min,max 日期相同,說(shuō)明只消費(fèi)了一次
(user_life['min']==user_life['max']).value_counts()
Out:
True 12054
False 11516
dtype: int64
結(jié)果顯示:
- 有約 50% 的用戶僅消費(fèi)一次拐云。
b. 每月新用戶占比
# 按month罢猪,user_id分組,求每月的第一次消費(fèi)日期和最后一次消費(fèi)日期
user_life_month = df.groupby(['month','user_id']).order_dt.agg(["min","max"])
# 新增new列叉瘩,True即為新用戶
user_life_month["new"] = (user_life_month["min"] == user_life_month["max"])
# 再次按month分組膳帕,計(jì)算新用戶占比
user_life_month_pct = user_life_month.groupby("month").new.apply(lambda x:x.value_counts()/x.count()).reset_index()
# 折線圖繪制
user_life_month_pct[user_life_month_pct.level_1].plot(x='month',y='new',figsize=(10, 4))
plt.title('用戶最后一次購(gòu)買時(shí)間分布')
plt.ylabel('百分比/%')
5.4 用戶分層
a. 構(gòu)建RFM模型
RFM模型是衡量客戶價(jià)值和客戶創(chuàng)利能力的重要工具和手段。該機(jī)械模型通過一個(gè)客戶的近期購(gòu)買行為房揭、購(gòu)買的總體頻率以及花了多少錢三項(xiàng)指標(biāo)來(lái)描述該客戶的價(jià)值狀況备闲。
- R(Recency):客戶最近一次交易時(shí)間的間隔。R值越大捅暴,表示客戶交易發(fā)生的日期越久恬砂,反之則表示客戶交易發(fā)生的日期越近。
- F(Frequency):客戶在最近一段時(shí)間內(nèi)交易的次數(shù)蓬痒。F值越大泻骤,表示客戶交易越頻繁,反之則表示客戶交易不夠活躍梧奢。
- M(Monetary):客戶在最近一段時(shí)間內(nèi)交易的金額狱掂。M值越大,表示客戶價(jià)值越高亲轨,反之則表示客戶價(jià)值越低趋惨。
# 畫RFM,先對(duì)原始數(shù)據(jù)進(jìn)行透視
rfm = df.pivot_table(index = 'user_id',
values = ['order_amount','order_dt','order_products'],
aggfunc = {'order_amount':'sum','order_dt':'max','order_products':'count'})
rfm.head()
Out:
order_amount order_dt order_products
user_id
1 11.77 1997-01-01 1
2 89.00 1997-01-12 2
3 156.46 1998-05-28 6
4 100.50 1997-12-12 4
5 385.61 1998-01-03 11
# 得到最近一次消費(fèi)惦蚊,一般是計(jì)算距離 today 最近的一次消費(fèi)器虾,這里因?yàn)闀r(shí)間太久遠(yuǎn),就使用 max值
# 時(shí)間格式相減蹦锋,結(jié)果是XXX days兆沙,除以一個(gè)單位'D'
rfm['R'] = -(rfm.order_dt - rfm.order_dt.max()) / np.timedelta64(1, 'D')
# 重命名:R-最后一次消費(fèi)距今天數(shù),F(xiàn)-消費(fèi)總商品數(shù)莉掂,M-消費(fèi)總金額
rfm.rename(columns = {'order_products': 'F', 'order_amount':'M'},inplace=True)
rfm.head()
Out:
M order_dt F R
user_id
1 11.77 1997-01-01 1 545.0
2 89.00 1997-01-12 2 534.0
3 156.46 1998-05-28 6 33.0
4 100.50 1997-12-12 4 200.0
5 385.61 1998-01-03 11 178.0
def rfm_func(x):
level = x.apply(lambda x:'1' if x>=0 else '0')
# level 的類型是 series葛圃,R、F憎妙、M是其索引
# 字符串拼接
label = level.R + level.F + level.M
d = {
# R 為1 表示比均值大库正,離最早時(shí)間近,F(xiàn)為1 表示 消費(fèi)金額比較多厘唾,M 為1 表示消費(fèi)頻次比較多诀诊,所以是重要價(jià)值客戶
'111':'重要價(jià)值客戶',
'011':'重要保持客戶',
'101':'重要發(fā)展客戶',
'001':'重要挽留客戶',
'110':'一般價(jià)值客戶',
'010':'一般保持客戶',
'100':'一般發(fā)展客戶',
'000':'一般挽留客戶'
}
result = d[label]
return result
# 這里是要一行行的進(jìn)行傳遞,所以 axis=1阅嘶,傳遞一行得到一個(gè) label,然后匹配返回一個(gè)值
rfm['label'] = rfm[['R', 'F', 'M']].apply(lambda x:x-x.mean()).apply(rfm_func,axis=1)
rfm.head()
Out:
M order_dt F R label
user_id
1 11.77 1997-01-01 1 545.0 一般發(fā)展客戶
2 89.00 1997-01-12 2 534.0 一般發(fā)展客戶
3 156.46 1998-05-28 6 33.0 重要保持客戶
4 100.50 1997-12-12 4 200.0 一般保持客戶
5 385.61 1998-01-03 11 178.0 重要保持客戶
# 圖形繪制
plt.figure(figsize=(10, 4))
for label,gropued in rfm.groupby('label'):
x = gropued['F']
y = gropued['R']
plt.scatter(x,y,label = label) # 利用循環(huán)繪制函數(shù)
plt.legend(loc='best') # 圖例位置
plt.xlabel('Frequency')
plt.ylabel('Recency')
結(jié)果顯示:
- 大部分用戶是“重要保持客戶”,但是這是由于極值的影響讯柔,所以 RFM 的劃分標(biāo)準(zhǔn)應(yīng)該以業(yè)務(wù)為準(zhǔn)抡蛙,也可以通過切比雪夫定理去除極值后求均值,并且 RFM 的各個(gè)劃分標(biāo)準(zhǔn)可以都不一樣魂迄。
- 盡量用小部分的用戶覆蓋大部分的額度
- 不要為了數(shù)據(jù)好看劃分等級(jí)
# 將“重要價(jià)值客戶”與“非重要價(jià)值客戶”進(jìn)行再次分類
rfm.loc[rfm.label=='重要價(jià)值客戶','color'] = '重要價(jià)值客戶'
rfm.loc[~(rfm.label=='重要價(jià)值客戶'),'color'] = '非重要價(jià)值客戶'
# 散點(diǎn)圖繪制
plt.figure(figsize=(10, 4))
for label,gropued in rfm.groupby('color'):
x = gropued['F']
y = gropued['R']
plt.scatter(x,y,label = label) # 利用循環(huán)繪制函數(shù)
plt.legend(loc='best') # 圖例位置
plt.xlabel('Frequency')
plt.ylabel('Recency')
結(jié)果顯示:
- 紅色部分為重要價(jià)值的客戶粗截,是需要重點(diǎn)維護(hù)對(duì)象。
# 各用戶層次總消費(fèi)金額捣炬、消費(fèi)頻次
rfm.groupby('label').sum()
Out:
M F R
label
一般價(jià)值客戶 36200.21 1782 237754.0
一般保持客戶 141127.20 7371 309037.0
一般發(fā)展客戶 409272.88 15589 6750356.0
一般挽留客戶 75781.48 3064 311519.0
重要價(jià)值客戶 103260.14 1950 194091.0
重要保持客戶 1591666.47 38490 517048.0
重要發(fā)展客戶 96849.09 877 278754.0
重要挽留客戶 46158.16 536 56855.0
結(jié)果顯示:
- “重要保持客戶”的消費(fèi)頻次和消費(fèi)金額最高熊昌,其次為“一般發(fā)展客戶”。
# 各用戶層次對(duì)應(yīng)的用戶人數(shù)
rfm.groupby('label').count()
Out:
M order_dt F R
label
一般價(jià)值客戶 543 543 543 543
一般保持客戶 1974 1974 1974 1974
一般發(fā)展客戶 13608 13608 13608 13608
一般挽留客戶 1532 1532 1532 1532
重要價(jià)值客戶 449 449 449 449
重要保持客戶 4617 4617 4617 4617
重要發(fā)展客戶 579 579 579 579
重要挽留客戶 268 268 268 268
結(jié)果顯示:
- “一般發(fā)展客戶”這一層次的用戶最多湿酸,為 13608 人婿屹,其次為“重要保持客戶”。
b. 新推溃、老昂利、活躍、回流铁坎、流失
# 通過每月是否消費(fèi)來(lái)劃分用戶蜂奸,缺失值用0填充
pivoted_counts = df.pivot_table(index = 'user_id',
columns = 'month',
values = 'order_dt',
aggfunc = 'count').fillna(0)
pivoted_counts.columns = df.month.sort_values().astype('str').unique() # 將month數(shù)據(jù)類型轉(zhuǎn)換為str
pivoted_counts.head()
Out:
1997-01-01 1997-02-01 1997-03-01 1997-04-01 1997-05-01 1997-06-01 1997-07-01 1997-08-01 1997-09-01 1997-10-01 1997-11-01 1997-12-01 1998-01-01 1998-02-01 1998-03-01 1998-04-01 1998-05-01 1998-06-01
user_id
1 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
2 2.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
3 1.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0
4 2.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0
5 2.0 1.0 0.0 1.0 1.0 1.0 1.0 0.0 1.0 0.0 0.0 2.0 1.0 0.0 0.0 0.0 0.0 0.0
# 轉(zhuǎn)變一下消費(fèi),有消費(fèi)為1硬萍,沒有消費(fèi)為0
df_purchase = pivoted_counts.applymap(lambda x: 1 if x> 0 else 0)
df_purchase.head()
Out:
1997-01-01 1997-02-01 1997-03-01 1997-04-01 1997-05-01 1997-06-01 1997-07-01 1997-08-01 1997-09-01 1997-10-01 1997-11-01 1997-12-01 1998-01-01 1998-02-01 1998-03-01 1998-04-01 1998-05-01 1998-06-01
user_id
1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
3 1 0 1 1 0 0 0 0 0 0 1 0 0 0 0 0 1 0
4 1 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0
5 1 1 0 1 1 1 1 0 1 0 0 1 1 0 0 0 0 0
# 這里由于進(jìn)行數(shù)據(jù)透視扩所,填充了一些 null 值為0,而實(shí)際可能用戶在當(dāng)月根本就沒有注冊(cè)朴乖,這樣會(huì)誤導(dǎo)第一次消費(fèi)數(shù)據(jù)的統(tǒng)計(jì)祖屏,所以寫一個(gè)函數(shù)來(lái)處理
def active_status(data):
status = []
# 數(shù)據(jù)一共有18個(gè)月份,每次輸入一行數(shù)據(jù)寒砖,這樣進(jìn)行逐月判斷
for i in range(18):
# 若本月沒有消費(fèi)
if data[i] == 0:
# 判斷之前沒有數(shù)據(jù)赐劣,若之前有數(shù)據(jù)
if len(status) > 0:
# 判斷上個(gè)月是否為未注冊(cè)(如果上個(gè)月未注冊(cè),本月沒有消費(fèi)哩都,仍為未注冊(cè))
if status[i-1] == 'unreg':
status.append('unreg')
# 上月有消費(fèi)魁兼,本月沒有消費(fèi),則為不活躍
else:
status.append('unactive')
# 之前一個(gè)數(shù)據(jù)都沒有漠嵌,就認(rèn)為是未注冊(cè)
else:
status.append('unreg')
# 若本月有消費(fèi)
else:
# 若之前無(wú)記錄咐汞,本月是第一次消費(fèi),則為新用戶
if len(status) == 0:
status.append('new')
# 若之前有記錄
else:
# 若上個(gè)月是不活躍儒鹿,這個(gè)月消費(fèi)了化撕,則為回流用戶
if status[i-1] == 'unactive':
status.append('return')
# 若上個(gè)月未注冊(cè),這個(gè)月消費(fèi)了约炎,則為新用戶
elif status[i-1] == 'unreg':
status.append('new')
# 若上個(gè)月消費(fèi)了植阴,本月仍消費(fèi)蟹瘾,則為活躍用戶
else:
status.append('active')
return status
用戶活躍狀態(tài)active_status判斷說(shuō)明:
若本月沒有消費(fèi),這里只是和上個(gè)月判斷是否注冊(cè)掠手,有一定的缺陷憾朴,應(yīng)該判斷是否存在就可以了
- 若之前有數(shù)據(jù),是未注冊(cè)喷鸽,則依舊為未注冊(cè)
- 若之前有數(shù)據(jù)众雷,不是未注冊(cè),則為流失/不活躍
- 若之前沒有數(shù)據(jù)做祝,為未注冊(cè)
若本月有消費(fèi)
- 若是第一次消費(fèi)砾省,則為新用戶
- 若之前有過消費(fèi),上個(gè)月為不活躍混槐,則為回流
- 若之前有過消費(fèi)编兄,上個(gè)月為未注冊(cè),則為新用戶
- 若之前有過消費(fèi)纵隔,其他情況為活躍
purchase_states = df_purchase.apply(active_status,axis = 1)
purchase_states.head()
Out:
1997-01-01 1997-02-01 1997-03-01 1997-04-01 1997-05-01 1997-06-01 1997-07-01 1997-08-01 1997-09-01 1997-10-01 1997-11-01 1997-12-01 1998-01-01 1998-02-01 1998-03-01 1998-04-01 1998-05-01 1998-06-01
user_id
1 new unactive unactive unactive unactive unactive unactive unactive unactive unactive unactive unactive unactive unactive unactive unactive unactive unactive
2 new unactive unactive unactive unactive unactive unactive unactive unactive unactive unactive unactive unactive unactive unactive unactive unactive unactive
3 new unactive return active unactive unactive unactive unactive unactive unactive return unactive unactive unactive unactive unactive return unactive
4 new unactive unactive unactive unactive unactive unactive return unactive unactive unactive return unactive unactive unactive unactive unactive unactive
5 new active unactive return active active active unactive return unactive unactive return active unactive unactive unactive unactive unactive
# 將未注冊(cè) unreg 數(shù)據(jù)替換為空值翻诉,這樣count不會(huì)計(jì)算到,得到每個(gè)月的用戶分布
purchase_states_ct = purchase_states.replace('unreg',np.NaN).apply(lambda x:pd.value_counts(x))
purchase_states_ct
Out:
1997-01-01 1997-02-01 1997-03-01 1997-04-01 1997-05-01 1997-06-01 1997-07-01 1997-08-01 1997-09-01 1997-10-01 1997-11-01 1997-12-01 1998-01-01 1998-02-01 1998-03-01 1998-04-01 1998-05-01 1998-06-01
active NaN 1157.0 1681 1773.0 852.0 747.0 746.0 604.0 528.0 532.0 624.0 632.0 512.0 472.0 571.0 518.0 459.0 446.0
new 7846.0 8476.0 7248 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
return NaN NaN 595 1049.0 1362.0 1592.0 1434.0 1168.0 1211.0 1307.0 1404.0 1232.0 1025.0 1079.0 1489.0 919.0 1029.0 1060.0
unactive NaN 6689.0 14046 20748.0 21356.0 21231.0 21390.0 21798.0 21831.0 21731.0 21542.0 21706.0 22033.0 22019.0 21510.0 22133.0 22082.0 22064.0
# 轉(zhuǎn)置捌刮,并用 0 填充 NaN 值
purchase_states_ct.fillna(0).T.head()
Out:
active new return unactive
1997-01-01 0.0 7846.0 0.0 0.0
1997-02-01 1157.0 8476.0 0.0 6689.0
1997-03-01 1681.0 7248.0 595.0 14046.0
1997-04-01 1773.0 0.0 1049.0 20748.0
1997-05-01 852.0 0.0 1362.0 21356.0
# 繪制面積圖碰煌,描述用戶分布
purchase_states_ct.fillna(0).T.plot.area(figsize=(10,4))
結(jié)果顯示:
- 藍(lán)色區(qū)域代表新用戶,前3個(gè)月大量涌入绅作,后期沒有新增芦圾;
- 紅色區(qū)域代表的活躍用戶非常穩(wěn)定,是屬于核心用戶俄认;
- 紫色區(qū)域代表回流用戶个少,與紅色區(qū)域這兩部分之和就是消費(fèi)用戶人數(shù)占比;
- 灰色區(qū)域代表不活躍用戶眯杏。
c. 回流用戶占比
# 每月各類用戶占比
rate = purchase_states_ct.fillna(0).T.apply(lambda x:x/x.sum())
rate.head()
Out:
active new return unactive
1997-01-01 0.000000 0.332881 0.000000 0.000000
1997-02-01 0.090011 0.359610 0.000000 0.019337
1997-03-01 0.130776 0.307510 0.031390 0.040606
1997-04-01 0.137934 0.000000 0.055342 0.059981
1997-05-01 0.066283 0.000000 0.071854 0.061739
# 折線圖繪制
plt.figure(figsize=(20, 8))
plt.plot(rate['return'],label='return')
plt.plot(rate['active'],label='active')
plt.title('回流&活躍用戶占比')
plt.xlabel('month')
plt.ylabel('百分比/%')
plt.legend()
結(jié)果顯示:
- 用戶每月回流用戶比占 5% ~ 8% 之間夜焦,有下降趨勢(shì),說(shuō)明用戶有流失傾向岂贩;
- 活躍用戶的占比在 3% ~ 5% 間茫经,下降趨勢(shì)更顯著,活躍用戶可以看作連續(xù)消費(fèi)用戶萎津,忠誠(chéng)度高于回流用戶卸伞。
5.5 用戶消費(fèi)周期(按訂單)
a. 用戶消費(fèi)周期描述
# 錯(cuò)行相減計(jì)算相鄰兩個(gè)訂單的時(shí)間間隔,shift 函數(shù)是對(duì)數(shù)據(jù)進(jìn)行錯(cuò)位锉屈,所有數(shù)據(jù)會(huì)往下平移一下
order_diff = grouped_user.apply(lambda x:x.order_dt - x.order_dt.shift())
order_diff.head(10)
Out:
user_id
1 0 NaT
2 1 NaT
2 0 days
3 3 NaT
4 87 days
5 3 days
6 227 days
7 10 days
8 184 days
4 9 NaT
Name: order_dt, dtype: timedelta64[ns]
# 描述性統(tǒng)計(jì)
order_diff.describe()
count 46089
mean 68 days 23:22:13.567662
std 91 days 00:47:33.924168
min 0 days 00:00:00
25% 10 days 00:00:00
50% 31 days 00:00:00
75% 89 days 00:00:00
max 533 days 00:00:00
Name: order_dt, dtype: object
b. 用戶消費(fèi)周期分布
# 直方圖繪制
plt.figure(figsize=(10, 4))
(order_diff / np.timedelta64(1, 'D')).hist(bins = 20)
plt.title('用戶消費(fèi)周期直方圖')
plt.xlabel('天數(shù)/天')
plt.ylabel('人數(shù)/人')
結(jié)果顯示:
- 訂單周期呈指數(shù)分布荤傲;
- 用戶的平均購(gòu)買周期是 68 天;
- 絕大部分用戶的購(gòu)買周期低于 100 天颈渊。
5.6 用戶生命周期
a. 用戶生命周期描述
# 用戶生命周期 = 最后一次購(gòu)買時(shí)間 - 第一次購(gòu)買時(shí)間
user_life = grouped_user.order_dt.agg(['min', 'max'])
user_life.head()
Out:
min max
user_id
1 1997-01-01 1997-01-01
2 1997-01-12 1997-01-12
3 1997-01-02 1998-05-28
4 1997-01-01 1997-12-12
5 1997-01-01 1998-01-03
# 用戶生命周期描述
(user_life['max'] - user_life['min']).describe()
Out:
count 23570
mean 134 days 20:55:36.987696
std 180 days 13:46:43.039788
min 0 days 00:00:00
25% 0 days 00:00:00
50% 0 days 00:00:00
75% 294 days 00:00:00
max 544 days 00:00:00
dtype: object
結(jié)果顯示:
- 用戶平均生命周期 134 天遂黍;
- 用戶生命周期中位數(shù)僅為 0 天终佛,大部分用戶僅消費(fèi)1次,這部分用戶屬于低質(zhì)量用戶妓湘;
- 用戶最大生命周期的為 544 天查蓉,幾乎是數(shù)據(jù)集的總天數(shù),該用戶屬于核心用戶榜贴。
b. 用戶生命周期分布
# 直方圖繪制
plt.figure(figsize=(10,4))
((user_life['max'] - user_life['min']) / np.timedelta64(1, 'D')).hist(bins = 40)
plt.title('用戶生命周期直方圖')
plt.xlabel('天數(shù)/天')
plt.ylabel('人數(shù)/人')
結(jié)果顯示:
- 生命周期為0,即僅消費(fèi)1次的用戶對(duì)結(jié)果分布影響較大妹田,可以將這部分用戶篩選掉唬党。
# 直方圖繪制
plt.figure(figsize=(10,4))
u_l = ((user_life['max'] - user_life['min']).reset_index()[0] / np.timedelta64(1,'D'))
u_l[u_l > 0].hist(bins = 40) # 篩選掉生命周期為0的用戶
plt.title('消費(fèi)2次以上用戶生命周期直方圖')
plt.xlabel('天數(shù)/天')
plt.ylabel('人數(shù)/人')
plt.axvline(x = u_l[u_l > 0].mean() ,ls = "--",c = "green",lw = 1) # 消費(fèi)兩次以上用戶平均生命周期
u_l[u_l > 0].describe()
Out:
count 11516.000000
mean 276.044807
std 166.633990
min 1.000000
25% 117.000000
50% 302.000000
75% 429.000000
max 544.000000
Name: 0, dtype: float64
結(jié)果顯示:
- 用戶生命周期分布呈雙峰結(jié)構(gòu);
- 消費(fèi)兩次以上的用戶平均生命周期是 276 天鬼佣,遠(yuǎn)高于總體的134天驶拱;
- 在用戶首次消費(fèi)后引導(dǎo)其進(jìn)行多次消費(fèi),可以有效提高用戶生命周期晶衷。
6.復(fù)購(gòu)率和回購(gòu)率分析
復(fù)購(gòu)率:自然月內(nèi)蓝纲,購(gòu)買多次的用戶占比。
回購(gòu)率:曾經(jīng)購(gòu)買的用戶在某一時(shí)期內(nèi)的再次購(gòu)買的占比晌纫。
6.1 復(fù)購(gòu)率
# 消費(fèi)兩次及以上為 1 税迷,消費(fèi)1次為 0 ,沒有消費(fèi)為空
purchase_r = pivoted_counts.applymap(lambda x: 1 if x > 1 else np.NaN if x==0 else 0)
# 復(fù)購(gòu)率 = 復(fù)購(gòu)人數(shù) / 總消費(fèi)人數(shù)(不計(jì)算NaN值)
repurchase_rate = purchase_r.sum() / purchase_r.count()
repurchase_rate.head()
Out:
1997-01-01 0.107571
1997-02-01 0.122288
1997-03-01 0.155292
1997-04-01 0.223600
1997-05-01 0.196929
dtype: float64
# 折線圖繪制
plt.figure(figsize=(10, 4))
plt.title('復(fù)購(gòu)率')
plt.xlabel('month')
plt.ylabel('百分比/%')
repurchase_rate.plot()
結(jié)果顯示:
- 復(fù)購(gòu)率穩(wěn)定在 20% 左右锹漱,前三個(gè)月因?yàn)橛写罅啃掠脩粲咳爰@批用戶只購(gòu)買了一次,所以導(dǎo)致復(fù)購(gòu)率降低哥牍。
6.2 回購(gòu)率
# 回購(gòu):當(dāng)月消費(fèi)的用戶在下個(gè)月消費(fèi)
def purchase_back(data):
status = []
for i in range(17):
# 若本月消費(fèi)
if data[i] == 1:
# 若下個(gè)月回購(gòu)
if data[i+1] == 1:
status.append(1)
# 若下個(gè)月沒回購(gòu)
if data[i+1] == 0:
status.append(0)
# 若本月沒消費(fèi)毕泌,賦予空值,不參與計(jì)算
else:
status.append(np.NaN)
# 第18個(gè)月補(bǔ)充NaN嗅辣,因?yàn)闆]有下個(gè)月的數(shù)據(jù)
status.append(np.NaN)
return status
# 0:當(dāng)月消費(fèi)下個(gè)月未消費(fèi)撼泛,1:當(dāng)月消費(fèi)下個(gè)月仍消費(fèi),NaN:當(dāng)月未消費(fèi)
purchase_b = df_purchase.apply(purchase_back,axis = 1)
# 回購(gòu)率 = 回購(gòu)次數(shù) / 總購(gòu)買次數(shù)
repurchasing = purchase_b.sum() / purchase_b.count()
repurchasing.head()
Out:
1997-01-01 0.147464
1997-02-01 0.174504
1997-03-01 0.186161
1997-04-01 0.301914
1997-05-01 0.337398
dtype: float64
plt.figure(figsize=(20,8))
plt.subplot(211)
(purchase_b.sum() / purchase_b.count()).plot()
plt.title('用戶回購(gòu)率圖')
plt.ylabel('百分比%')
# 繪制用戶每月消費(fèi)&回購(gòu)折線圖
plt.subplot(212)
plt.plot(purchase_b.sum(),label='每月回購(gòu)人數(shù)')
plt.plot(purchase_b.count(),label='每月消費(fèi)人數(shù)')
plt.xlabel('month')
plt.ylabel('人數(shù)')
plt.legend()
結(jié)果顯示:
- 用戶回購(gòu)率高于復(fù)購(gòu)率澡谭,約在 30% 左右愿题,波動(dòng)性較強(qiáng)。
- 新用戶回購(gòu)率在 15 % 左右译暂,與老用戶相差不大抠忘。
- 回購(gòu)人數(shù)在前三月之后趨于穩(wěn)定。
7.留存率分析
# 每一次消費(fèi)距第一次消費(fèi)的時(shí)間差值
user_purchase = df[['user_id','order_products','order_amount','order_dt']]
# 表連接外永,與用戶最早消費(fèi)時(shí)間進(jìn)行連接
user_purchase_retention = pd.merge(left = user_purchase,
right = user_life['min'].reset_index(),
how = 'inner',
on = 'user_id')
# # 新增“order_dt_diff”列崎脉,等于每一次消費(fèi)距第一次消費(fèi)的時(shí)間差值
user_purchase_retention['order_dt_diff'] = user_purchase_retention['order_dt']-user_purchase_retention['min']
# 新增“dt_diff”列,去掉單位“days”
user_purchase_retention['dt_diff'] = user_purchase_retention.order_dt_diff.apply(lambda x: x/np.timedelta64(1,'D'))
user_purchase_retention.head()
Out:
user_id order_products order_amount order_dt min order_dt_diff dt_diff
0 1 1 11.77 1997-01-01 1997-01-01 0 days 0.0
1 2 1 12.00 1997-01-12 1997-01-12 0 days 0.0
2 2 5 77.00 1997-01-12 1997-01-12 0 days 0.0
3 3 2 20.76 1997-01-02 1997-01-02 0 days 0.0
4 3 2 20.76 1997-03-30 1997-01-02 87 days 87.0
user_purchase_retention['dt_diff_bin'] = pd.cut(user_purchase_retention.dt_diff, bins = bin)
user_purchase_retention.head()
Out:
user_id order_products order_amount order_dt min order_dt_diff dt_diff dt_diff_bin
0 1 1 11.77 1997-01-01 1997-01-01 0 days 0.0 NaN
1 2 1 12.00 1997-01-12 1997-01-12 0 days 0.0 NaN
2 2 5 77.00 1997-01-12 1997-01-12 0 days 0.0 NaN
3 3 2 20.76 1997-01-02 1997-01-02 0 days 0.0 NaN
4 3 2 20.76 1997-03-30 1997-01-02 87 days 87.0 (60, 90]
pivoted_retention = user_purchase_retention.groupby(['user_id','dt_diff_bin']).order_amount.sum().unstack()
pivoted_retention.head()
Out:
dt_diff_bin (0, 30] (30, 60] (60, 90] (90, 120] (120, 150] (150, 180] (180, 365]
user_id
3 NaN NaN 40.3 NaN NaN NaN 78.41
4 29.73 NaN NaN NaN NaN NaN 41.44
5 13.97 38.90 NaN 45.55 38.71 26.14 155.54
7 NaN NaN NaN NaN NaN NaN 97.43
8 NaN 13.97 NaN NaN NaN 45.29 104.17
# 時(shí)間差值分桶伯顶,代表用戶當(dāng)前消費(fèi)時(shí)間距離第一次消費(fèi)時(shí)間差屬于哪個(gè)時(shí)間段
bin = [0,30,60,90,120,150,180,365]
# 新增列“dt_diff_bin”將消費(fèi)時(shí)間差分配到對(duì)應(yīng)的分桶中
# 用戶僅消費(fèi)1次囚灼,dt_diff = 0骆膝,并不會(huì)劃分到0-30分桶中,用戶在一天消費(fèi)多次之后沒有消費(fèi)灶体,dt_diff = 0
user_purchase_retention['dt_diff_bin'] = pd.cut(user_purchase_retention.dt_diff, bins = bin)
user_purchase_retention.head()
user_id order_products order_amount order_dt min order_dt_diff dt_diff dt_diff_bin
0 1 1 11.77 1997-01-01 1997-01-01 0 days 0.0 NaN
1 2 1 12.00 1997-01-12 1997-01-12 0 days 0.0 NaN
2 2 5 77.00 1997-01-12 1997-01-12 0 days 0.0 NaN
3 3 2 20.76 1997-01-02 1997-01-02 0 days 0.0 NaN
4 3 2 20.76 1997-03-30 1997-01-02 87 days 87.0 (60, 90]
# 按user_id 和 dt_diff_bin 進(jìn)行分組阅签,unstack:將數(shù)據(jù)的行“旋轉(zhuǎn)”為列
pivoted_retention = user_purchase_retention.groupby(['user_id','dt_diff_bin']).order_amount.sum().unstack()
pivoted_retention_trans = pivoted_retention.fillna(0).applymap(lambda x: 1 if x >0 else 0)
pivoted_retention_trans.head()
Out:
dt_diff_bin (0, 30] (30, 60] (60, 90] (90, 120] (120, 150] (150, 180] (180, 365]
user_id
3 0 0 1 0 0 0 1
4 1 0 0 0 0 0 1
5 1 1 0 1 1 1 1
7 0 0 0 0 0 0 1
8 0 1 0 0 0 1 1
# 各分桶用戶平均消費(fèi)金額
pivoted_retention.mean()
Out:
dt_diff_bin
(0, 30] 51.540649
(30, 60] 50.215070
(60, 90] 48.975277
(90, 120] 48.649005
(120, 150] 51.399450
(150, 180] 49.932592
(180, 365] 91.960059
dtype: float64
結(jié)果顯示:
- 時(shí)間跨度越大,分桶用戶消費(fèi)金額越高蝎抽;
- 雖然后面時(shí)段的消費(fèi)更高政钟,但是其時(shí)間跨度也更大。從平均效果看樟结,用戶第一次消費(fèi)后的 0~30 天养交,可能消費(fèi)更多。
# 用戶留存用戶率 =月留存用戶 / 總留存用戶
retention_rate = (pivoted_retention_trans.sum()/pivoted_retention_trans.count())*100
retention_rate
Out:
dt_diff_bin
(0, 30] 38.057354
(30, 60] 28.279371
(60, 90] 21.739130
(90, 120] 19.888992
(120, 150] 19.333950
(150, 180] 18.556892
(180, 365] 56.743756
dtype: float64
# 柱狀圖繪制
plt.figure(figsize=(10,4))
retention_rate.plot.bar()
plt.ylabel('百分比/%')
plt.xlabel('留存時(shí)間')
plt.title('用戶留存率')
結(jié)果顯示:
- 第一個(gè)月的留存率達(dá)到 38%瓢宦,第二個(gè)月就下降到 28% 左右碎连,之后幾個(gè)月趨于穩(wěn)定;
- 有 20% 左右的用戶在第一次購(gòu)買后的三個(gè)月到半年之間有過消費(fèi)記錄驮履;
- 有 57% 左右的用戶在半年以后鱼辙,一年以內(nèi)有過消費(fèi)記錄。
五玫镐、總結(jié)
- 用戶消費(fèi)趨勢(shì)(每月)方面倒戏,前3個(gè)月有大量新用戶涌入,消費(fèi)金額摘悴、消費(fèi)訂單數(shù)峭梳、產(chǎn)品購(gòu)買量均達(dá)到高峰,后續(xù)每月較為穩(wěn)定蹂喻。前3個(gè)月消費(fèi)次數(shù)都在10000筆左右葱椭,后續(xù)月份的平均2500;前3個(gè)月產(chǎn)品購(gòu)買量達(dá)到20000甚至以上口四,后續(xù)月份平均7000孵运;前3個(gè)月消費(fèi)人數(shù)在8000-10000之間,后續(xù)月份平均2000不到蔓彩。
- 用戶個(gè)體消費(fèi)方面治笨,小部分用戶購(gòu)買了大量的CD,拉高了平均消費(fèi)金額赤嚼。用戶消費(fèi)金額集中在0100元旷赖,有大約17000名用戶。用戶購(gòu)買量集中在05更卒,有大約16000名用戶等孵。50%的用戶僅貢獻(xiàn)了15%的消費(fèi)額度,15%的用戶貢獻(xiàn)了60%的消費(fèi)額度蹂空。大致符合二八法則俯萌。
- 用戶消費(fèi)行為方面果录,首購(gòu)和最后一次購(gòu)買的時(shí)間,集中在前三個(gè)月咐熙,說(shuō)明很多用戶購(gòu)買了一次后就不再進(jìn)行購(gòu)買弱恒。而且最后一次購(gòu)買的用戶數(shù)量也在隨時(shí)間遞增,消費(fèi)呈現(xiàn)流失上升的狀況棋恼。
- 從整體消費(fèi)記錄來(lái)看返弹,有一半的用戶,只消費(fèi)了一次蘸泻。從每月新用戶占比來(lái)看琉苇,1997年1月新用戶占比高達(dá)90%以上,后續(xù)有所下降悦施,1997年4月到1998年6月維持在81%左右,1998年6月以后無(wú)新用戶去团。
- 從RFM模型來(lái)看抡诞,在8種客戶中,重要保持客戶的消費(fèi)頻次和消費(fèi)金額最高土陪,人數(shù)排在第二位昼汗;而一般發(fā)展客戶消費(fèi)頻次和消費(fèi)金額排第二位,人數(shù)卻是最多鬼雀。
- 從用戶分層情況來(lái)看顷窒,新用戶從第4月份以后沒有新增;活躍用戶有所下降源哩;回流用戶數(shù)量趨于穩(wěn)定鞋吉,每月1000多。流失/不活躍用戶励烦,數(shù)量非常多谓着,基本上每月都在20000以上。
- 用戶購(gòu)買周期方面坛掠,平均購(gòu)買周期是68天赊锚,最小值0天,最大值533天屉栓。絕大部分用戶的購(gòu)買周期都低于100天舷蒲。
- 用戶生命周期方面,由于只購(gòu)買一次的用戶(生命周期為0天)占了接近一半友多,排除這部分用戶的影響之后牲平,用戶平均生命周期276天,中位數(shù)302天夷陋。
- 復(fù)購(gòu)率和回購(gòu)率方面欠拾,復(fù)購(gòu)率穩(wěn)定在20%左右胰锌,回購(gòu)率穩(wěn)定在30%左右,前3個(gè)月因?yàn)橛写罅啃掠脩粲咳朊暾@批用戶只購(gòu)買了一次资昧,所以導(dǎo)致復(fù)購(gòu)率和回購(gòu)率都比較低。
- 用戶留存率方面荆忍,用戶的第一個(gè)月留存率為38%格带,第二個(gè)月下降到28%,后趨于穩(wěn)定刹枉;有 20% 左右的用戶在第一次購(gòu)買后的三個(gè)月到半年之間有過消費(fèi)記錄叽唱;有 57% 左右的用戶在半年以后,一年以內(nèi)有過消費(fèi)記錄微宝;距離上一次購(gòu)買時(shí)間越大的用戶棺亭,平均消費(fèi)金額越高。