數據分析項目:用戶消費行為分析


數據源於CDNOW網站的用戶購買記錄,通過以下字段利用python對CD銷售數據分析

分析需要基於業務,首先需要對數據進行了解

數據字段包括

  • user_ud 用戶ID
  • order_dt: 購買日期
  • order_products: 購買產品數
  • order_amount: 購買金額

鏈接:CDNOW數據(點我)    提取碼:zvum 

分析思路: 0:數據准備階段(數據預處理) 1:按月數據分析 2:用戶個體消費分析 3:用戶消費行為分析
4:復購率,回購率分析

  0:數據准備

導入常用的數據庫

 

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
plt.rcParams['font.sans-serif']=['SimHei'] #用來正常顯示中文標簽

 導入數據,設置相應字段

1 columns = ['user_id','order_dt','order_products','order_amount']
2 data = pd.read_table('CDNOW_master.txt',names=columns,sep='\s+')
# 查看數據
data.head()
# 大概格式了解
data.info()
# 數據字段
  • user_ud 用戶ID
  • order_dt: 購買日期
  • order_products: 購買產品數
  • order_amount: 購買金額

 

數據中無缺失值,無需對缺失值處理,但是購買日期的數據類型是int,為方便后面數據處理,在這先將其轉化成datetime格式

data['order_dt'] = pd.to_datetime(data.order_dt,format='%Y%m%d')
# 新增一個月 (對月進行分析) values(數組形式) 因為很多是進行月份的一個處理
data['month'] = data.order_dt.values.astype('datetime64[M]')

處理好后,查看數據,此時數據時間轉換為正常格式

data.info()

# describe是描述統計
data.describe()

  • 觀察數據,用戶平均訂單必輸2.4個商品,標准差為2.3,略有波動,中位數書為2個商品,說明絕大部分訂單的購買量不多,最大值為99,有一定的極值干擾
  • 用戶消費均值35元左右,中位數25元,最大金額達到了1286元,有一定極值干擾
  1:按月數據分析
  • 每月消費總金額
  • 每月消費次數
  • 每月產品購買量
  • 每月的消費人數
# 按月分組
grouped_month = data.groupby('month')

fig = plt.figure(figsize = (8,12))
ax1 = fig.add_subplot(4,1,1)
ax2 = fig.add_subplot(4,1,2)
ax3 = fig.add_subplot(4,1,3)
ax4 = fig.add_subplot(4,1,4)
# 按月金額數
ax1.plot(grouped_month.order_amount.sum(),c='blue')
ax1.set_title('每月消費總金額變化趨勢')
# 按月的訂單數
ax2.plot(grouped_month.user_id.count(),c='blue')
ax2.set_title('每月訂單數變化趨勢')
# 按月產品數
ax3.plot(grouped_month.order_products.sum(),c='blue')
ax3.set_title('每月消費產品購買量')
# 每月用戶人數  這里需要去重,有些用戶重復購買
ax4.plot(grouped_month.user_id.apply(lambda x:len(x.drop_duplicates())),c='blue')
ax4.set_title('每月用戶數變化趨勢')
按月進行統計,下面通過折線圖分別查看數據變化趨勢

一:消費金額在前三個月達最高峰,或許消費金額較為平穩,有輕微下降趨勢

圖二:前三個月訂單數在10000筆左右,后續月份的訂單數在2500左右

圖三:產品購買量  呈現早期購買量多  后期下降趨勢

圖四:每月消費人數小小於每月的消費次數(訂單數),但是區別不大,前三個月每月的消費人數在8000-10000之間,后續月份平均2000左右,一樣是前期消費人數多,后期平穩下降趨勢

出現這種狀況,假設問題是出現在用戶身上,早期時間段的用戶有異常值,或者由於各類促銷營銷,由於只有消費數據,無法進一步進行判斷

 

數據透視查看,按月根據用戶購買金額,訂單數,用戶人數

data.pivot_table(index='month', values = ['order_products','order_amount','user_id'], aggfunc = {'order_products':'sum', 'order_amount':'sum', 'user_id':'count'})

 

 

  2.用戶個體消費分析

  • 用戶消費金額,消費次數描述統計
  • 用戶消費金額和消費次數的散點圖
  • 用戶消費金額的分布圖
  • 用戶消費次數的分布圖
  • 用戶累積消費金額占比(百分之多少的用戶占了百分之多少的消費額)

根據用戶維度進行分析

01-用戶消費金額和消費次數的描述統計
grouped_user = data.groupby('user_id') grouped_user.sum().describe()

  • 用戶平均購買量7張CD,標准差17,波動比較大,但是中位值只有3,說明小部分用戶購買了大量的CD
  • 用戶平均消費為106元,中位值為43,也有極值干擾
  • 消費的話一般都會符合二八法則

 

02 - 用戶消費金額和消費次數散點圖
# 設置排除一些極值的干擾進行觀察
grouped_user.sum().query('order_amount < 4000').plot.scatter(x='order_amount',y='order_products')

  • 繪制散點圖,由於產品比較單一,購買金額和產品數呈線性關系
03-用戶消費金額的分布圖(二八法則)
grouped_user.sum().order_amount.plot.hist(bins=20)
# bins=20,就是分成20塊,最高金額是14000,每個項就是700

  • 由直方圖可知,用戶消費金額,大部分消費金額能力確實不高,絕大部分呈幾種在很低的消費檔次,高消費用戶在圖中基本看不到,這也符合消費行為的行業規律
  • 小部分異常值干擾判斷,可以過濾操作排除異常
04-用戶消費次數分布圖
grouped_user.sum().query('order_products<92').order_products.hist(bins = 40)

 

  • 使用切比雪夫定理過濾異常值,計算95%的數據分布情況  (均值+5*標准差)
05 -用戶累計消費金額占比
user_cumsum = grouped_user.sum().sort_values('order_amount').apply(lambda x: x.cumsum() / x.sum()) user_cumsum.reset_index().order_amount.plot()

 

  • 通過觀察,50%的用戶僅僅貢獻了15%的消費額度,而排名前五千用戶就貢獻了%60的消費額
print(user_cumsum.head(8))
print(user_cumsum.tail(8))

  • 上面是一些累積占比的數據,數據中存在金額為0,可能是一些活動贈送等原因

 

  3.用戶消費行為分析

  • 用戶第一次消費(首購)
  • 用戶最后一次消費
  • 新老客戶消費比
    • 多少用戶僅僅消費了一次
    • 每月新客占比
  • 用戶分層
    • RFM
    • 新、老、活躍、回流、流失/不活躍
  • 用戶購買周期(按訂單)
    • 用戶消費周期描述
    • 用戶消費周期分布
  • 用戶生命周期(按第一次 & 最后一次消費)
    • 用戶生命周期描述
    • 用戶生命周期分布
01-第一次購買時間分布
#
min() 時間最小,第一次購買 grouped_user.min().order_dt.value_counts().plot() # 2月發生較大下跌 渠道發生變化,或者其他 可以做一些假設

  • 用戶第一次購買分布,集中在前三個月,其中2月11日至2月25日有一次劇烈波動
02-最后一次購買時間分布
grouped_user.max().order_dt.value_counts().plot()

  • 用戶最后一次購買的分布比第一次購買分布廣
  • 大部分最后一次購買在前三個月,說明很多用戶購買一次后就不再進行購買
  • 隨着時間遞增,最后一次購買數在遞增,消費呈線性流失上升的情況
03-用戶第一次購買與最后一次購買 新老客的消費比
user_life =grouped_user.order_dt.agg(['min','max']) user_life.head()

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

rate = (user_life['min'] == user_life['max']).value_counts()
labels = ['只消費一次用戶','多次消費用戶']
plt.axis('equal') # 保證長寬相等
plt.pie(rate,explode=(0,0.15),labels=labels,autopct='%2.1f%%',startangle=90,colors=['r','orange'],radius=1.5)

 

True 第一次購買時間和最后一次購買時間一樣,有一般用戶只消費了一次

04-用戶分層
#  RFM   消費額 次數  最近一次消費 進行透視
rfm = data.pivot_table(index = 'user_id',
                     values = ['order_products','order_amount','order_dt'],
                     aggfunc = {'order_dt':'max',
                                'order_amount':'sum',
                                'order_products':'sum'})
rfm.head()

# 表示離最近一次消費的時間間隔
-(rfm.order_dt - rfm.order_dt.max()).head()
# 數值越大,離現在的時間越長

# /np.timedelta64(1,'D')  消除單位   進行重命名
rfm['R'] = -(rfm.order_dt - rfm.order_dt.max()) / np.timedelta64(1,'D')
rfm.rename(columns = {'order_products':'F','order_amount':'M'},inplace=True)
rfm.head()

 

rfm[['R','F','M']].apply(lambda x:x-x.mean()).head()

數據解讀: 負數是小於的   正式大於的   

R:離最近一次購買的天數   F:產品數(消費次數) M:消費金額   與均值的對比

def rfm_func(x):
    level = x.apply(lambda x:'1' if x>= 0 else '0')
  # 字符串拼接
  # 111,R>0,是距離平均消費時間要久,R越大 說明沒有消費時間越久 ,F >0 M>0,消費次數和金額也是較高的,重要價值客戶,依次類推 label
= level.R + level.F + level.M d = { '111':'重要價值客戶', '011':'重要保持客戶', '101':'重要挽留客戶', '001':'重要發展客戶', '110':'一般價值客戶', '010':'一般保持客戶', '100':'一般挽留客戶', '000':'一般發展客戶' } result = d[label] return result # x - x.mean() (具體真實情況可以修改,不一定需要用均值) 切比雪夫也可以 > 200 極值人工處理掉 rfm['label'] = rfm[['R','F','M']].apply(lambda x:x-x.mean()).apply(rfm_func,axis=1)
rfm.head()

  

數據解讀: 1  時間比較長,只消費了一次,消費金額低   一般挽留客戶 

rfm.groupby('label').sum()

  

重要保持客戶貢獻了159萬左右  等等

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

  

# 各類類型用戶占比
use_c = rfm.groupby('label').count() plt.axis('equal') labels = ['一般價值客戶','一般保持客戶','一般發展客戶','一般挽留客戶','重要價值客戶','重要保持客戶','重要發展客戶','重要挽留客戶'] plt.pie(use_c['M'], autopct='%3.1f%%', labels = labels, pctdistance=0.9, labeldistance = 1.2, radius=3, startangle = 15)

 

# 對應標簽,使用不同顏色表示
# 綠色為重要價值客戶,紅色為非重要價值用戶
rfm.loc[rfm.label == '重要價值客戶','color'] = 'g' rfm.loc[~(rfm.label == '重要價值客戶'),'color'] = 'r' rfm.plot.scatter('F','R',c=rfm.color)

rfm.head()
# rfm 象限法

rfm.groupby('label').sum()

 

從RFM分層可知,大部分用戶為重要保持客戶,但是這是由於極值的影響,所以RFM的划分應該以業務微賺

  • 盡量用小部分的用戶覆蓋大部分的額度
  • 不要為了數據好看划分等級
  • 極值會拉均值
  • 根據數據可以和業務相結合,如何提升一些重要的指標
06-用戶生命周期
pivoted_counts = data.pivot_table(index = 'user_id', columns = 'month', values = 'order_dt', aggfunc = 'count').fillna(0) # pivoted_counts.head() pivoted_counts.head() # 按月份進行對比,1月份哪些是購買的,再去對比二月份哪些是購買的

消費過的為1 ,沒消費過的為0
data_purchase = pivoted_counts.applymap(lambda x: 1 if x > 0 else 0) data_purchase.tail() # 透視會補上 第一次從3月分開始購買 前面補成0 , 需要進行判,第一次消費作為生命周期的起始 # se.columns.values

def active_status(data):
    status = []
    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')
  # 這里需要對返回的值進行轉換,將列表轉為Series
return pd.Series(status, index = pivoted_counts.columns)
  • 若本月沒有消費
    • 若之前是未注冊,則依舊未注冊
    • 若之前有消費,則為流失/不活躍
    • 其他情況,為未注冊
  • 若本月有消費
    • 若是第一次消費,則為新用戶
    • 如果之前有過消費,則上個月為不活躍,則為回流
    • 如果上個月為未注冊,則為新用戶
    • 除此之外,為活躍
purchase_stats = data_purchase.apply(active_status,axis=1,result_type ='expand')
# df.rename(columns={ df.columns[2]: "new name" }, inplace=True)
# purchase_stats.rename(columns={purchase_stats.columns:data_purchase.columns})
purchase_stats.head()

purchase_status_ct = purchase_stats.replace('unreg',np.NaN).apply(lambda x : pd.value_counts(x))
purchase_status_ct
# 未注冊不希望參與處理  設置我空值

數據解讀: 一月份有7846個用戶   然后2月份分叉為不活躍用戶 和 活躍用戶    有8476個新用戶 等等

 新用戶轉換為是否活躍等等 流失用戶在增加

# 各個狀態的占比 
purchase_status_ct.fillna(0).T.apply(lambda x:x/x.sum(),axis=1)
purchase_status_ct.fillna(0).T.plot.area()

由上表可知,每月的用戶消費轉改變化

  • 活躍用戶,持續消費的用戶,對應的使消費運營質量
  • 回流用戶,之前不消費本月才消費,對應的使喚回運營
  • 不活躍用戶,對應的是流失
用戶購買周期 
data.order_dt.head(10)
# 把所有的數據進行一個錯位  DataFrame.shift 
data.order_dt.shift().head(10)

#   一個用戶可能多個訂單  每個訂單的間隔 
order_diff = grouped_user.apply(lambda x:x.order_dt - x.order_dt.shift())
order_diff.head(10)

 

數據解讀:ID為2     0天當天購買兩次或以上,間隔為0     

     ID為3的用戶          3-4間隔了87天   

NaT表示一個訂單

order_diff.describe()

 

每個用戶的平均訂單是68天  中位值31天 最大值533天

# 去除單位  間隔天數分布圖
(order_diff / np.timedelta64(1,'D')).hist(bins=20)
order_diff / np.timedelta64(1,'D')

(user_life['max'] - user_life['min']).describe()
# 整體的生命周期

((user_life['max'] - user_life['min']) / np.timedelta64(1,'D')).hist(bins = 40)

 

  • 用戶的生命周期受只購買一次的用戶影響比較厲害 (可以進行排除 當特殊情況,想提取出購買一次以上的用戶)
  • 用戶均消費134天,中位數僅為0
u_l = ((user_life['max'] - user_life['min']).reset_index()[0] / np.timedelta64(1,'D'))
u_l[u_l > 0].hist(bins=40)

  • 左邊比較高,還是有些用戶的生命周期是比較短的,例如10、20天等
  • 有不少用戶生命周期也是比較穩定

  4.復購率和回購率分析

  • 復購率
    • 自然月內,購買多次的用戶占比
  • 回購率
    • 曾今購買過的用戶在某一時期內的再次購買占比
pivoted_counts.head()

# 購買大於1次的 賦值為1 ,然后小於等於1 的 如果是購買次數是0,則賦值為空,否則 就是購買一次,賦值為0
purchase_r = pivoted_counts.applymap(lambda x: 1 if x > 1 else np.NaN if x == 0 else 0) purchase_r.head() 

# sum() 0 不計數,count() 0計數
(purchase_r.sum() / purchase_r.count()).plot(figsize = (10,4))

  • 復購率穩定在20% 左右,前三個月因為有大量新用戶涌入,而這些用戶只購買了一次,所以導致復購率較低
回購率 只需要0  1 代表
data_purchase.head()

def purchase_back(data):
    status = []
    for i in range(17):
        if data[i] == 1: # 本月進行過消費
            if data[i+1] == 1: # 下一月是否進行消費
                status.append(1) #消費為1 回購了
            if data[i+1] == 0:
                status.append(0) # 未消費則為0 沒有回購
        else:
            status.append(np.NaN) # 之前沒消費則不計
    status.append(np.NaN) # 最后一個月沒有判斷需要補上
    return pd.Series(status,data_purchase.columns)
purchase_b = data_purchase.apply(purchase_back, axis =1)
purchase_b.head(5)

 

  • 0 表示上個月購買了,下個月沒有進行消費,則是沒有回購 ,
  • 1代表當月消費過次月依舊消費,表示回購了
  • NAN表示當月沒有消費(不進行計算)
sum() 0 1進行求和,表示次月消費過的
(purchase_b.sum() / purchase_b.count()).plot(figsize = (10, 4))

  •  回購率在30%左右波動,比復購率要高,綜合分析得出,新客整體質量低於老客,老客忠誠度(回購率)表現較好,消費頻次稍次,這個是是CDNow網站的用戶消費特征

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM