目錄
前言
一. 數(shù)據(jù)預(yù)處理
1.1 數(shù)據(jù)導(dǎo)入
1.2 數(shù)據(jù)清洗二. 月用戶消費趨勢分析
2.1 每月消費總金額
2.2 每月訂單總數(shù)
2.3 每月消費總產(chǎn)品數(shù)
2.4 每月消費人數(shù)
2.5 每月用戶平均消費金額
2.6 每月用戶平均消費次數(shù)三. 用戶個體消費分析
3.1 用戶消費金額和次數(shù)的散點圖
3.2 用戶消費金額的分布圖
3.3 用戶消費次數(shù)的分布圖
3.4 用戶累計消費金額占比四. 用戶消費行為分析
4.1 用戶第一次消費(首購)
4.2 用戶最近一次消費
4.3 新老客消費比
4.4 用戶分層
前言
1、寫這篇報告的目的主要是為了練手,熟悉數(shù)據(jù)分析的流程,把前期學(xué)的python數(shù)據(jù)分析庫等理論知識應(yīng)用到實際項目中,加深對理論知識的掌握度。
2、數(shù)據(jù)來源于CDNow網(wǎng)站,為用戶購買CD的消費明細(xì)。
一. 數(shù)據(jù)預(yù)處理
先查看一下原始數(shù)據(jù):
每一行代表一個用戶訂單的購買明細(xì),共有用戶編號、購買日期、購買產(chǎn)品數(shù)量、訂單消費金額四個字段。但是原始數(shù)據(jù)中沒有包含表頭,我們導(dǎo)入數(shù)據(jù)時需要添加表頭。
1. 數(shù)據(jù)導(dǎo)入
import numpy as np
import pandas as pd
columns = [ 'user_id', 'order_dt', 'order_products', 'order_amount' ] # 定義表頭
df = pd.read_table('CDNOW_master.txt', names=columns, sep='\s+') # 分隔符為多個空格
此處注意原始數(shù)據(jù)使用空白符分割,需要指定分隔符,\s+代表任意多個空白符。
觀察數(shù)據(jù)樣本:
df.head()

查看數(shù)據(jù)類型信息,觀察數(shù)據(jù)是否被正確識別:
df.info()

發(fā)現(xiàn)購買日期order_dt為整數(shù)類型,需要進行數(shù)據(jù)清洗,將其轉(zhuǎn)換為日期類型。 沒有空值,不需要填補缺失值。
查看整體統(tǒng)計信息:
df.describe()

- 大部分訂單只購買了少量商品(平均2.4),50%的訂單購買商品數(shù)量了在2個及以下,75%的訂單購買商品數(shù)量在3個及以下,最多的訂單購買了99個商品,平均消費商品數(shù)量存在一定極值干擾;
- 訂單平均交易金額35元,中位數(shù)在25元,75%的訂單金額在43元及以下,訂單最大金額為1286,有一定極值干擾。
2. 數(shù)據(jù)清洗——類型轉(zhuǎn)化
將剛剛提到的購買日期order_dt轉(zhuǎn)化為時間類型:
df.order_dt = pd.to_datetime(df.order_dt, format='%Y%m%d')
再次查看數(shù)據(jù)信息:
order_dt成功轉(zhuǎn)化為時間類型。
二. 月用戶消費趨勢分析
因為是按月分析,所以新增一個月份字段并查看數(shù)據(jù)樣本:
df['month'] = df.order_dt.values.astype('datetime64[M]')
df.head()

可以看到month精確到了月份,后面的日都變成了1號。然后按月分組數(shù)據(jù):
grouped_month = df.groupby('month')
2.1 每月消費總金額
order_amount_month = grouped_month.order_amount.sum()
# 或者order_amount_month = grouped_month[['order_amount']].agg(['sum'])
order_amount_month.head()

可視化每月消費總金額情況:
import matplotlib.pyplot as pet
%matplotlib inline
plt.style.use('ggplot') # 使用設(shè)計風(fēng)格ggplot
order_amount_month.plot()

消費金額在前三個月達(dá)到最高峰,之后急劇下降,1997年4月份之后每月消費總金額比較平穩(wěn),有輕微下降趨勢。
2.2 每月訂單總數(shù)
grouped_month.user_id.count().plot()

前三個月訂單總數(shù)量平均為10000筆左右,后續(xù)月份平均每個月的訂單量在2500筆左右。
2.3 每月消費總產(chǎn)品數(shù)
grouped_month.order_products.sum().plot()

前三個月消費總產(chǎn)品數(shù)達(dá)到最高峰,平均為24000左右,后續(xù)月份平均每月消費產(chǎn)品量約在6000左右。
2.1、2.2、2.3的結(jié)果也可以通過透視圖獲得:
pt = df.pivot_table(index = 'month',
values = [ 'order_products', 'order_amount', 'user_id' ],
aggfunc = {'order_products' : 'sum',
'order_amount' : 'sum',
'user_id' : 'count'})
pt.order_amount.plot()
pt.order_products.plot()
pt.user_id.plot()
2.4 每月消費人數(shù)
同一個月中一個用戶可能消費多次,需要去除掉重復(fù)的user_id。
方法一
grouped_month.user_id.nunique().plot()
方法二
grouped_month.user_id.apply(lambda x : len( x.drop_duplicates() ) ).plot() # 同一個月中一個用戶可能消費多次,需要去除掉重復(fù)的user_id
方法三:
df.groupby([ 'month', 'user_id']).count().reset_index().groupby('month').user_id.count().plot() # 先按照月份和用戶ID分組達(dá)到對用戶ID去重的目的

- 每月消費人數(shù)低于每月訂單總數(shù)(即每月消費次數(shù)),但差異不大;
- 前三個月每月的消費人數(shù)在8000-10000人左右,后續(xù)月份平均消費人數(shù)不足2000。
2.5 每月用戶平均消費金額
# 每月用戶平均消費金額 = 總金額 / 每月消費總?cè)藬?shù)
grouped_month.apply( lambda x : x.order_amount.sum() / x.user_id.nunique() ).plot()

前三個月平均金額稍低,后續(xù)月份每月用戶平均消費金額在47-57之間波動,變化不大。
2.6 每月用戶平均消費次數(shù)
# 每月用戶平均消費次數(shù) = 每月訂單總量 / 每月消費總?cè)藬?shù)
grouped_month.apply( lambda x : x.user_id.count() / x.user_id.nunique() ).plot()

- 每月用戶平均消費頻次在1.13-1.15之間,前三個月由于用戶大量涌入,部分用戶可能僅消費了一次,導(dǎo)致頻次略低;
- 后續(xù)月份用戶平均消費頻次比較平穩(wěn),且略高于前3個月。
三. 用戶個體消費分析
觀察用戶消費金額、購買產(chǎn)品數(shù)量的描述統(tǒng)計:
grouped_user = df.groupby('user_id')
grouped_user.sum().describe()

- 平均每用戶購買了7張CD,但是中位數(shù)只有3,說明小部分用戶購買了大量CD;
- 用戶平均消費106元,中位值為43,75%分位數(shù)為106,剛好等于平均消費,有25%的用戶消費的比平均金額多,再看最大消費金額為13990(CD狂熱愛好者?。糇C了上面小部分用戶購買了大量CD的結(jié)論,數(shù)據(jù)存在極值干擾。
3.1 用戶消費金額和消費次數(shù)的散點圖
grouped_user.sum().plot.scatter(x = 'order_products', y = 'order_amount' )

可以看到最后面兩個極值的存在拉大了圖形區(qū)域,使得密集區(qū)域集中在左下角。通過過濾排除極值干擾:
grouped_user.sum().query('order_products < 350').plot.scatter(x = 'order_products', y = 'order_amount')

散點圖呈現(xiàn)明顯的線性關(guān)系,可以推測CD產(chǎn)品比較單一,單價比較穩(wěn)定。
3.2 用戶消費金額的分布圖
grouped_user.sum().order_amount.plot.hist(bins = 100)
plt.xlabel('order_amount') # 設(shè)置x軸的名稱

從直方圖可知,用戶消費金額,絕大部分呈現(xiàn)集中趨勢,大部分用戶消費金額在1500以內(nèi),小部分異常值干擾了判斷。
使用切比雪夫定律(95%的數(shù)據(jù)位于其平均值+5標(biāo)準(zhǔn)差范圍之內(nèi))過濾異常值,由3.1的用戶消費金額及購買產(chǎn)品數(shù)量的描述性統(tǒng)計可知,95%的用戶消費金額位于106+5240=1306范圍內(nèi):
grouped_user.sum().query('order_amount < 1306').order_amount.plot.hist(bins = 20)

3.3 用戶消費次數(shù)的分布圖
同上,獲取過濾掉極值之后的用戶購買產(chǎn)品數(shù)量分布:
grouped_user.sum().query('order_products < 100').order_products.plot.hist(bins = 20)

可以看出,大部分用戶僅購買了1-5張CD,整體購買數(shù)量和消費金額成指數(shù)下降趨勢。
3.4 用戶累計消費金額占比(百分之多少的用戶占了百分之多少的消費額)
user_cumsum = grouped_user.sum().sort_values('order_amount').apply(lambda x : x.cumsum() / x.sum()) # 對每一列應(yīng)用apply里面的函數(shù)
user_cumsum.reset_index().order_amount.plot() # 重新設(shè)置索引方便作圖,x軸為索引

50%的用戶僅貢獻(xiàn)了約15%的消費額,消費金額排名靠前的20%用戶貢獻(xiàn)了60%的消費額。
四. 用戶消費行為分析
4.1 用戶第一次消費(首購)
備注:首購是一個比較重要的維度,它和渠道等息息相關(guān), 尤其是客單價比較高用戶留存率又比較低的行業(yè), 可以通過首購分析第一次購買的用戶渠道,然后拓展出運營的方式。
通過對用戶第一次購買時間最小值的統(tǒng)計獲取用戶首購時間分布情況:
grouped_user.min().order_dt.value_counts().plot()

用戶第一次購買時間集中在前三個月,其中在2月中旬的時候有一次比較大的波動。
4.2 用戶最近一次消費
grouped_user.max().order_dt.value_counts().plot()

- 用戶最后一次購買的分布比第一次分布廣;
- 大部分用戶最后一次購買時間,集中在前三個月,說明很多用戶購買了一次后就不再購買;
- 隨著時間的遞增,最后一次購買數(shù)量也在遞增,消費呈現(xiàn)流失上升的狀況。
4.3 新老客消費比
4.3.1 多少用戶僅消費了一次
求出用戶的購買時間的最大值和最小值,若相等,說明用戶僅消費了一次:
user_life = grouped_user.order_dt.agg(['min', 'max'])
user_life.head()

(user_life['min'] == user_life['max']).value_counts()

超過一半的用戶,僅消費了一次。
4.3.2 每月新客占比
grouped_month_user = df.groupby(['month', 'user_id']) # 按月和用戶ID分組
tmp = grouped_month_user.order_dt.agg(['min']).join(grouped_user.order_dt.min()) # 求出用戶在當(dāng)月首購時間和用戶在所有時間段的首購時間
tmp['is_new'] = (tmp['min'] == tmp['order_dt']) # 新增一列,是否首購時間在當(dāng)月,即是否為新客
tmp.reset_index().groupby('month').apply(lambda x : x.is_new.sum() / x.user_id.count() ).plot() # 計算新客占比

新客集中在前三個月,后面消費的均為老用戶。
4.4 用戶分層
R:最近一次消費時間
F:消費頻率
M:消費金額
通過透視表獲取用戶RFM相關(guān)維度的信息:
rfm = df.pivot_table(index = 'user_id',
values = [ 'order_products', 'order_amount', 'order_dt' ],
aggfunc = {'order_dt' : 'max',
'order_amount' : 'sum',
'order_products' : 'sum'})
rfm.head()

求出相應(yīng)的R、F、M:
rfm['R'] = (rfm.order_dt.max() - rfm.order_dt) /np.timedelta64(1, 'D') # 把所有用戶order_dt的最大值作為現(xiàn)在的時間,求出距今天數(shù)
rfm.rename(columns = {'order_products' : 'F', 'order_amount' : 'M'}, inplace = True)
rfm.head()

將用戶在R、F、M三個維度上分為低于平均額度和高于平均額度的用戶(劃分標(biāo)準(zhǔn)根據(jù)不同業(yè)務(wù)設(shè)計不同):
rfm[['R', 'F', 'M']].apply(lambda x : x - x.mean()).head()

給用戶打標(biāo)簽:
def rfm_label(x): # 對每一行數(shù)據(jù)根據(jù)其rfm的值求出其label
level = x.apply(lambda x : '1' if x >= 0 else '0')
label = level.R + level.F + level.M
d = {
'111' : '重要價值客戶',
'011' : '重要保持客戶',
'101' : '重要發(fā)展客戶',
'001' : '重要保持客戶',
'110' : '一般價值客戶',
'010' : '一般保持客戶',
'100' : '一般發(fā)展客戶',
'000' : '一般挽留客戶'
}
result = d[label]
return result
rfm['label'] = rfm[['R', 'F', 'M']].apply(lambda x : x - x.mean()).apply(rfm_label, axis = 1)
ram.head()

可以看到,用戶已經(jīng)都打上了相應(yīng)的標(biāo)簽。
rfm.groupby('label').sum()

rfm.groupby('label').count()

從RFM分層結(jié)果可知,“重要保持客戶”為主要利潤來源,即最后一次消費時間越晚,消費頻次越高,消費額度越高的用戶是優(yōu)質(zhì)客戶。
用不同顏色區(qū)分不同標(biāo)簽的用戶:
rfm.loc[ rfm.label == '重要保持客戶', 'color'] = 'brown'
rfm.loc[ rfm.label == '重要發(fā)展客戶', 'color'] = 'grey'
rfm.loc[ rfm.label == '重要價值客戶', 'color'] = 'c'
rfm.loc[ rfm.label == '重要挽留客戶', 'color'] = 'r'
rfm.loc[ rfm.label == '一般保持客戶', 'color'] = 'k'
rfm.loc[ rfm.label == '一般發(fā)展客戶', 'color'] = 'y'
rfm.loc[ rfm.label == '一般價值客戶', 'color'] = 'm'
rfm.loc[ rfm.label == '一般挽留客戶', 'color'] = 'w'
rfm.plot.scatter('F', 'R', c=rfm.color)

從圖中可以看到大部分用戶的購買頻次在200以內(nèi),少部分的極值可能會對我們使用平均值劃分RFM造成一定程度的偏差(平均值對大部分用戶來說偏大),所以如果使用平均值劃分應(yīng)該考慮到先根據(jù)切比雪夫定律剔除極值。