python案例——cd消費(fèi)用戶行為分析

前言:

存在一份用戶在一家cd網(wǎng)站上的消費(fèi)記錄,對此進(jìn)行消費(fèi)情況及用戶行為分析。
數(shù)據(jù)樣式:


image.png

數(shù)據(jù)來源:
鏈接:https://pan.baidu.com/s/1l68MIJil0-kZQg5DAxIcdg
提取碼:w50i

具體步驟:
1.數(shù)據(jù)清洗
2.進(jìn)行用戶行為銷售分析(按月):每月消費(fèi)總額、次數(shù)、產(chǎn)品購買量、人數(shù)
3.用戶個(gè)體消費(fèi)分析:重點(diǎn)關(guān)注消費(fèi)金額和消費(fèi)次數(shù)情況
4.用戶消費(fèi)行為分析:首購、最后一次購買、用戶分層(新老客、RFM)、用戶購買周期、用戶生命周期
5.用戶回購率和復(fù)購率分析

數(shù)據(jù)清洗:

1.導(dǎo)入常用包及數(shù)據(jù)集

import pandas as pd
import numpy as np

columns = ['user_id','order_dt','order_products','order_amount']
df = pd.read_table('CDNOW_master.txt',names = columns , sep= "\s+")
image.png

2.檢查數(shù)據(jù)并清洗整理

df.info() #order_dt int64 為整數(shù)型 需改成日期型
image.png
df['order_dt']=pd.to_datetime(df.order_dt,format="%Y%m%d")
df['month']=df.order_dt.values.astype("datetime64[M]") #astype 轉(zhuǎn)換格式
image.png

按月分析故新列【month】字段

一、進(jìn)行用戶消費(fèi)趨勢分析(按月)

1.每月的消費(fèi)總金額

grouped_month = df.groupby('month')
order_month_amount=grouped_month.order_amount.sum()
order_month_amount.head()
image.png

導(dǎo)入可視化包

#加載數(shù)據(jù)可視化包
import matplotlib.pyplot as plt
#可視化顯示在頁面,%代表內(nèi)置命令,inline 顯示圖標(biāo)
%matplotlib inline
# 更改設(shè)計(jì)風(fēng)格
plt.style.use('ggplot')
order_month_amount.plot() #plot為折線圖

image.png

由上圖可知,消費(fèi)金額在前三個(gè)月達(dá)到最高分,后續(xù)消費(fèi)金額較為平穩(wěn),有輕微下降趨勢
2.每月的消費(fèi)次數(shù)

grouped_month.user_id.count().plot()
image.png

前三個(gè)月消費(fèi)訂單數(shù)在10000筆左右,后續(xù)月份的平均消費(fèi)人數(shù)則在2500人

3.每月的產(chǎn)品購買量

grouped_month.order_products.sum().plot()

image.png

前三個(gè)月產(chǎn)品購買數(shù)在20000以上,后續(xù)月份的產(chǎn)品購買量在6000~8000左右 。
4.每月的消費(fèi)人數(shù)

df.groupby("month").user_id.apply(lambda x:len(x.drop_duplicates())).plot() 

image.png

每月消費(fèi)人數(shù)低于每月消費(fèi)次數(shù),但差異不大 前三個(gè)月每月的消費(fèi)人數(shù)在8000-10000之間,后續(xù)月份平均消費(fèi)人數(shù)在2000人不到
5.直接利用數(shù)據(jù)透視表分析消費(fèi)金額、產(chǎn)品購買量、消費(fèi)次數(shù)

pivot_df=df.pivot_table(index ="month",
              values = ["order_products","order_amount","user_id"],
               aggfunc = {"order_products":'sum',
                         "order_amount":"sum",
                          "user_id":"count"}).head()
#數(shù)據(jù)透視表進(jìn)行去重操作比較麻煩,不建議
image.png
pivot_df.plot()
image.png

二、用戶個(gè)體消費(fèi)分析

1.用戶消費(fèi)金額、消費(fèi)次數(shù)的描述統(tǒng)計(jì)

grouped_user = df.groupby('user_id')
grouped_user.sum().describe()

image.png

用戶平均購買了5.39張CD,但是中位數(shù)只有1,說明小部分用戶購買了大量的CD
用戶平均消費(fèi)3.7元,中位值有7.37,判斷同上,有極值干擾
2.用戶消費(fèi)金額和消費(fèi)的散點(diǎn)圖

grouped_user.sum().plot.scatter(x = "order_amount",y = "order_products")
image.png
grouped_user.sum().query("order_amount<4000000").plot.scatter(x = "order_amount",y = "order_products")

image.png

3.用戶消費(fèi)金額的分布圖

grouped_user.sum().order_amount.plot.hist(bins = 20) #bins是分組,分20個(gè)組
image.png

從直方圖可知,用戶消費(fèi)金額,絕大部分呈現(xiàn)幾種趨勢,部分異常值干擾了判斷??梢允褂眠^濾操作排除異常

grouped_user.sum().query("order_products < 92").order_amount.plot.hist(bins = 40) 
image.png

使用切比雪夫定理過濾異常值,計(jì)算95%的數(shù)據(jù)的分布情況。 mean ± 5std (order_products 7+17*5=92)

4.用戶累計(jì)消費(fèi)金額占比(百分之多少的用戶占了百分值多少的消費(fèi)額)

user_cumsum = grouped_user.sum().sort_values("order_amount").apply(lambda x:x.cumsum()/x.sum())
user_cumsum.reset_index().order_amount.plot(figsize = (10,2)) #reset_index()去掉索引 方便作圖
image.png

按用戶消費(fèi)金額進(jìn)行升序排列,由圖可知 50% 的用戶 僅貢獻(xiàn)了15%的消費(fèi)額度。而排名前5000的用戶貢獻(xiàn)了60%的消費(fèi)額度。

三、用戶消費(fèi)行為

1.用戶第一次消費(fèi)(首購)

grouped_user.min().order_dt.value_counts().plot() #最小時(shí)間,距離用戶最遙遠(yuǎn),就是第一次購買的時(shí)間,value_counts()計(jì)數(shù)每天的個(gè)數(shù)
image.png

用戶第一次購買分布,集中在前三個(gè)月
其中,在2月11日至2月25日有一次劇烈波動(dòng)

2.用戶最后一次消費(fèi)

grouped_user.max().order_dt.value_counts().plot()
image.png

用戶最后一次購買的分布比第一次分布廣
大部分最后一次購買,集中在前三個(gè)月,說明很多用戶購買了一次后就不再進(jìn)行購買

3.新老客消費(fèi)比

3.1多少用戶僅消費(fèi)了一次?

user_life = grouped_user.order_dt.agg(["min","max"])
user_life.head()
image.png
(user_life["min"] == user_life["max"]).value_counts()
image.png

有一半用戶,就消費(fèi)了一次

3.2每月新客戶占比?

grouped_um = df.groupby(['month','user_id']).order_dt.agg(["min","max"])     #按月分組下的userid分組,求每月的最早購買日期和最晚消費(fèi)日期
grouped_um["new"] = (grouped_um["min"] == grouped_um["max"] )                # 新增列 True 為 新用戶

grouped_um.reset_index().groupby("month").new.value_counts()
image.png
grouped_um.reset_index().groupby("month").new.count()
image.png
grouped_um1 = grouped_um.reset_index().groupby("month") #重新按月分組
grouped_um2 = grouped_um1["new"].apply(lambda x : x.value_counts()/x.count()).reset_index() #求新老用戶占比
grouped_um2
image.png
grouped_um2[grouped_um2["level_1"]].plot(y = 'new', x ="month")  #利用布爾值篩選True 作圖
image.png

97年3至4月新用戶數(shù)量由90%跌落80%,后幾個(gè)月新用戶量保持在80~82%區(qū)間,1998年6月后再無新用戶

4.用戶分層-RFM

image.png

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()
image.png
 -(rfm.order_dt - rfm.order_dt.max()) # 最早時(shí)間與最晚時(shí)間差
image.png
rfm["R"] = -(rfm.order_dt - rfm.order_dt.max()) / np.timedelta64(1,"D") #/np.timedelta64(1,"D") 換成浮點(diǎn)數(shù)
rfm.rename(columns = {"order_products":"F","order_amount":"M"},inplace = True) #inplace 代表 是否覆蓋原始二維表
rfm[["R","F","M"]].apply(lambda x : x-x.mean())
image.png
def rfm_func(x):
    level = x.apply(lambda x:"1" if x>0  else "0")
    label = level.R + level.F +level.M
    d = {
        "111":"重要價(jià)值客戶",
        "011":"重要保持客戶",
        "101":"重要發(fā)展客戶",
        "001":"重要挽留客戶",
        "110":"一般價(jià)值客戶",
        "010":"一般挽留客戶",
        "100":"一般發(fā)展客戶",
        "000":"一般挽留客戶"
    }
    result = d[label]
    return result
rfm['label'] = rfm [["R","F","M"]].apply(lambda x: x-x.mean()).apply(rfm_func,axis = 1) #axis = 1是逐行應(yīng)用
image.png
rfm.loc[rfm.label == '重要價(jià)值客戶','color'] = 'g'     #green
rfm.loc[~(rfm.label == '重要價(jià)值客戶'),'color'] = 'r' #red
rfm.plot.scatter("F","R",c=rfm.color) 
image.png
rfm.groupby('label').sum()
image.png

從RFM分層可知,大部分用戶為重要保持客戶,但是這是由于極值的影響,所以RFM的劃分標(biāo)準(zhǔn)應(yīng)該以業(yè)務(wù)為準(zhǔn)

盡量用小部分的用戶覆蓋大部分的額度
不要為了數(shù)據(jù)好看劃分等級

5.用戶分層-新、活躍、回流、消失

pivoted_counts=df.pivot_table(index = "user_id",
                              columns = "month",
                              values = "order_dt",
                              aggfunc = "count").fillna(0)
pivoted_counts.head()
image.png
df_purchase = pivoted_counts.applymap(lambda x: 1 if x>0 else 0) #簡化模型,只需判斷是否存在 即 1與0
df_purchase.tail ()  #判斷尾部數(shù)據(jù) 是從 3月份才開始第一次購買
image.png
def active_status(data):
    status = []
    for i in range(18):  #12+6個(gè)月
    
        #若本月沒有消費(fèi)
        if data[i] == 0:
            if len(status) > 0:                 #判斷 存在記錄的話時(shí)
                if status[i-1] == "unreg":      #unreg 未注冊
                    status.append("unreg")
                else:
                    status.append("unactive")   # 如果前一個(gè)為 unreg 未注冊,則后一個(gè)應(yīng)判斷為不活躍
            else:
                status.append("unreg")         #不存在記錄時(shí),加入 unreg
            
        #若本月消費(fèi)
        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
image.png

若本月沒有消費(fèi)

  • 若之前是未注冊,則依舊為未注冊
  • 若之前有消費(fèi),則為流失/不活躍
  • 其他情況,為未注冊

若本月有消費(fèi)

  • 若是第一次消費(fèi),則為新用戶
  • 如果之前有過消費(fèi),則上個(gè)月為不活躍,則為回流
  • 如果上個(gè)月為未注冊,則為新用戶
  • 除此之外,為活躍
indexs=df['month'].sort_values().astype('str').unique()  #astype 的區(qū)別
purchase_stats = df_purchase.apply(lambda x:pd.Series(active_status(x),index=indexs),axis=1)
purchase_stats.head(5)
image.png
purchase_stats.tail(5)
image.png
purchase_stats_ct1 = purchase_stats.apply(lambda x:pd.value_counts(x))  #注意unreg區(qū)別
purchase_stats_ct1
image.png

流失用戶(unactive)正在增加
新用戶暫停
活躍用戶越來越少
運(yùn)營差

purchase_stats_ct.fillna(0).T.head()  #fillna將空值填充為0,  .T轉(zhuǎn)置
image.png
purchase_stats_ct.fillna(0).T.plot.area()   #.plot.area()面積圖
image.png
purchase_stats_ct.fillna(0).T.apply(lambda x:x/x.sum(),axis =1)
image.png

由上表可知,每月的用戶消費(fèi)狀態(tài)變化

  • 活躍用戶,持續(xù)消費(fèi)的用戶,對應(yīng)的是消費(fèi)運(yùn)營的質(zhì)量
  • 回流用戶,之前不消費(fèi)本月才消費(fèi),對應(yīng)的是喚回運(yùn)營
  • 不活躍用戶,對應(yīng)的是流失

6.用戶購買周期(按訂單)

  • 用戶消費(fèi)周期描述
  • 用戶消費(fèi)周期分布
df.head(10)
image.png
order_diff = grouped_user.apply(lambda x : x.order_dt -x.order_dt.shift()) #grouped_user = df.groupby('user_id'),shift() 為 兩個(gè)日期錯(cuò)行相減
order_diff.head(10)      #目的是求 時(shí)間差值 
image.png
order_diff.describe()     #會(huì)自動(dòng)過濾空值,對時(shí)間差值進(jìn)行描述統(tǒng)計(jì)分析
image.png
(order_diff / np.timedelta64(1,"D")).hist(bins = 20)
image.png
  • 訂單周期呈指數(shù)分布
  • 用戶的平均購買周期是68天
  • 絕大部分用戶的購買周期都低于100天

7.用戶生命周期(按第一次&最后一次消費(fèi))

  • 用戶生命周期描述
  • 用戶生命周期分布


    image.png
(user_life["max"] - user_life["min"]).describe()
image.png
((user_life["max"] - user_life["min"])/np.timedelta64(1,"D")).hist(bins = 40)
image.png

用戶的生命周期受只購買一次的用戶影響比較厲害(可以排除)
用戶均消費(fèi)134天,中位數(shù)僅0天

user_life["差值"]=(user_life["max"] - user_life["min"])
user_life.head()
image.png
user_life["差值"]=(user_life["max"] - user_life["min"])/np.timedelta64(1,"D")
user_life.head(5)
image.png
user_life.query("差值>0")["差值"].hist(bins = 40)
image.png

四、復(fù)購率和回購率分析

復(fù)購率

  • 自然月內(nèi),購買多次的用戶占比
    回購率
  • 曾經(jīng)購買過的用戶在某一時(shí)期內(nèi)的的再次購買的占比
pivoted_counts.head()
image.png
purchase_r = pivoted_counts.applymap(lambda x: 1 if x>1 else np.NaN if x== 0 else 0 ) 
purchase_r.head()
image.png
(purchase_r.sum()/purchase_r.count()).plot(figsize = (10,4)) #寬為10 高為4 , sum()對于1的求和,count()過濾掉np.Nan
image.png

復(fù)購率穩(wěn)定在20%左右,前三個(gè)月因?yàn)橛写罅啃掠脩粲咳耄@批用戶只購買了一次,所以導(dǎo)致復(fù)購率降低

df_purchase.head()
image.png
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)
    status.append(np.NaN)  #需注意 語句中的是 第一位與第二位相比 輸出結(jié)構(gòu)放第一位, 循環(huán)17次,17/18的判斷結(jié)束后,輸出的status僅17個(gè),需補(bǔ)上最后一個(gè)
    return status
#1代表 本月購買及下個(gè)月購買 ,sum()可計(jì)算 ,0代表 本月購買,下個(gè)月未購買 count()可計(jì)算總?cè)藬?shù), 回購率: 本月及下月購買/本月購買人群
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.head()
image.png
(purchase_b.sum()/purchase_b.count()).plot(figsize = (10,4))
image.png

絕大部分用戶購買一次后不再購買,老用戶回購率在30%徘徊

總結(jié)

1.cd網(wǎng)站的用戶在前三個(gè)月內(nèi)涌入絕大多數(shù)新用戶,其前三個(gè)月的平均消費(fèi)次數(shù)為10000筆左右,消費(fèi)人次達(dá)8000~10000左右,后續(xù)的消費(fèi)次數(shù)及人次下跌至2000左右。

2.根據(jù)二八法則,50%的用戶僅貢獻(xiàn)了15%的消費(fèi)額度,而消費(fèi)金額前5000名用戶貢獻(xiàn)了60%消費(fèi)額度,同時(shí)根據(jù)用戶購買次數(shù),平均購買7張CD,而中位數(shù)只有3,說明小部分用戶購買大量的CD,符合上述二八法則的分析。

3.根據(jù)用戶首次購買、最后購買及新老客占比分析,絕大部分用戶購買在前三個(gè)月,且購買一次就不再進(jìn)行購買,這部分客戶占50%(符合2的50%用戶僅貢獻(xiàn)15%消費(fèi)額度)。

4.根據(jù)每月新用戶占比分析,3至4月的新用戶占比由90%跌落80%,后幾個(gè)月新用戶量保持在80%到82%區(qū)間,1998年6月后再無新用戶,前三個(gè)月新用戶平均8000人左右,后續(xù)新用戶在1000至1500人波動(dòng)。

5.根據(jù)用戶分層-RFM分析,重要價(jià)值客戶的消費(fèi)金額高,但近期消費(fèi)下降,大部分為重要保持客戶。

6.按用戶購買時(shí)間分析,用戶平均購買周期68天,絕大部分用戶購買周期都低于100天。

7.根據(jù)復(fù)購率和回購率分析,復(fù)購率穩(wěn)定在20%左右,回購率穩(wěn)定在30%左右。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容