CD網(wǎng)站用戶消費(fèi)行為分析

一、簡(jiǎn)介

對(duì)國(guó)外某一CD網(wǎng)站的用戶購(gòu)買數(shù)據(jù)進(jìn)行分析,主要圍繞整體消費(fèi)情況和用戶消費(fèi)行為進(jìn)行分析,找出高價(jià)值用戶人群亭引,了解用戶留存以及流失等情況,為平臺(tái)指定策略提供數(shù)據(jù)方面的支持和建議皮获。

二焙蚓、流程

1、數(shù)據(jù)清洗
2洒宝、用戶消費(fèi)趨勢(shì)分析:觀察用戶月消費(fèi)額购公、月消費(fèi)趨勢(shì)以及總體消費(fèi)人數(shù)的變動(dòng)情況
3、用戶個(gè)體消費(fèi)分析:關(guān)注用戶消費(fèi)金額以及消費(fèi)次數(shù)的情況
4雁歌、用戶消費(fèi)行為分析:新老客比例宏浩,首購(gòu)及末購(gòu)情況,RFM用戶分層等
5靠瞎、復(fù)購(gòu)率比庄、回購(gòu)率分析

三、具體分析過(guò)程

1乏盐、數(shù)據(jù)清洗

導(dǎo)入數(shù)據(jù)包佳窑,同時(shí)設(shè)置好列標(biāo)簽

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+')
df
image.png

可以發(fā)現(xiàn)該數(shù)據(jù)集總共有69659行*4列數(shù)據(jù),4張列標(biāo)簽分別是
user_id:用戶id
order_dt:下單日期
order_products:購(gòu)買商品數(shù)量
order_amount:購(gòu)買金額

df.info()
image.png

order_dt字段為數(shù)值型父能,需要將其更改為日期型,同時(shí)加入month列神凑,作為備用

# 轉(zhuǎn)換為日期格式
df['order_dt'] = pd.to_datetime(df.order_dt, format="%Y%m%d")
df['month'] = df.order_dt.values.astype('datetime64[M]')
df.info()
image.png
  • pd.to_datetime可以將特定字符串或數(shù)字轉(zhuǎn)換為時(shí)間格式,其中format參數(shù)用于匹配

  • 例如19970701何吝,%Y匹配前面4位數(shù)字溉委,如果y小寫就只匹配2位數(shù)字97

  • 同理鹃唯,%m匹配月份07,%d匹配日期01薛躬。另外俯渤,小時(shí)是%h呆细,分鐘是%M

df.describe()
image.png

再來(lái)簡(jiǎn)單觀察數(shù)據(jù)集統(tǒng)計(jì)情況型宝,可以發(fā)現(xiàn)大部分訂單只消費(fèi)了少量商品(平均2.4個(gè)),同時(shí)用戶消費(fèi)金額比較穩(wěn)定絮爷,平均消費(fèi)35.89元趴酣,但是中位數(shù)在25.98元,最大值有1286元坑夯,說(shuō)明存在極值干擾的情況

2岖寞、用戶消費(fèi)趨勢(shì)的分析

1)月消費(fèi)金額

先對(duì)消費(fèi)金額按月進(jìn)行統(tǒng)計(jì)

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

利用matplotlib進(jìn)行圖表展示

# 加載數(shù)據(jù)可視化包
import matplotlib.pyplot as plt
# 可視化結(jié)果顯示在頁(yè)面
%matplotlib inline
# 更改設(shè)計(jì)風(fēng)格
plt.style.use('ggplot')
order_month_amount.plot()
image.png

可以發(fā)現(xiàn),顧客消費(fèi)金額在前三月達(dá)到了頂峰柜蜈,之后出現(xiàn)了明顯的回落仗谆,但是能保持在較穩(wěn)定的水平

2)月訂單數(shù)量

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

在訂單數(shù)量方面,其走勢(shì)也和消費(fèi)金額大體一致淑履,前三月在11000左右隶垮,后期回落到了2500左右的水平

3)月消費(fèi)人數(shù)

df.groupby('month').user_id.apply(lambda x: len(x.drop_duplicates())).plot()
image.png

用drop duplicates對(duì)user_id字段進(jìn)行去重,從而觀察每月消費(fèi)人數(shù)情況秘噪,可以發(fā)現(xiàn)前三月消費(fèi)人數(shù)在8000到10000之間狸吞,后續(xù)月份消費(fèi)人數(shù)大幅回落,平均消費(fèi)人數(shù)不足2000

3指煎、用戶個(gè)體消費(fèi)分析

1)用戶消費(fèi)描述統(tǒng)計(jì)

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

用戶平均購(gòu)買了7張CD蹋偏,但是中位數(shù)只有3,說(shuō)明有小部分用戶購(gòu)買了大量CD
用戶平均消費(fèi)金額106元至壤,中位數(shù)為43威始,同樣存在極值的干擾

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

利用散點(diǎn)圖對(duì)極值敏感的特點(diǎn),可以直觀發(fā)現(xiàn)極值的存在

2)用戶消費(fèi)金額分布情況

# hist為直方圖像街,bins為分組黎棠,此處分為20組
grouped_user.sum().order_amount.plot.hist(bins = 20)
image.png

從直方圖可知,用戶消費(fèi)金額絕大部分呈現(xiàn)集中趨勢(shì)宅广,小部分異常值干擾了判斷葫掉,可以使用過(guò)濾操作來(lái)排除異常

# 加入過(guò)濾條件
grouped_user.sum().query('order_products < 92').order_amount.hist(bins = 20)
image.png

使用切比雪夫定理來(lái)過(guò)濾異常值,計(jì)算95%數(shù)字的情況(order_products平均值為7跟狱,標(biāo)準(zhǔn)差為17俭厚,7+5*17=92)

3)用戶累計(jì)消費(fèi)占比情況

# cumsum求累加值
user_cumsum = grouped_user.sum().sort_values('order_amount').apply(lambda x:x.cumsum() / x.sum())
user_cumsum.reset_index().order_amount.plot()
image.png

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

4挪挤、用戶消費(fèi)行為分析

1)用戶首購(gòu)及末購(gòu)情況

# 得到最小日期善茎,再統(tǒng)計(jì)各個(gè)日期的個(gè)數(shù)
grouped_user.min().order_dt.value_counts().plot()
image.png

可以發(fā)現(xiàn),用戶第一次購(gòu)買集中分布在前三個(gè)月肥照,其中在2月11日至2月25日有一次劇烈波動(dòng)

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

而在最后一次購(gòu)買方面嚷闭,日期分布明顯要比首購(gòu)寬廣,但是大量最后一次購(gòu)買行為集中在前三個(gè)月论寨,說(shuō)明有大量用戶只購(gòu)買了一次之后便不再購(gòu)買星立。
隨著時(shí)間遞增,最后一次購(gòu)買數(shù)量也在遞增葬凳,消費(fèi)呈現(xiàn)流失上升的狀況

2)用戶生命周期

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ā)現(xiàn)有一半用戶只消費(fèi)了一次

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

可以看到用戶生命周期受極值的影響非常厲害绰垂,中位數(shù)僅有0天,但是平均首購(gòu)與末購(gòu)相隔天數(shù)為134天火焰,而且圖表中數(shù)據(jù)也集中于0天上

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

將首購(gòu)與末購(gòu)相隔天數(shù)大于0的單獨(dú)挑出來(lái)進(jìn)行觀察劲装,可以發(fā)現(xiàn)有接近1200名用戶兩次消費(fèi)間隔天數(shù)約在25天內(nèi),間隔400到500天的也有很大一部分

3)用戶分層——RFM模型

# 先對(duì)原始數(shù)據(jù)進(jìn)行透視
rfm = df.pivot_table(index='user_id',
                    values=['order_products', 'order_amount', 'order_dt'],
                    aggfunc={'order_products':'sum',
                            'order_amount':'sum',
                            'order_dt':'max'
                            })
rfm.head()
image.png
 # 將最早時(shí)間與最晚時(shí)間差轉(zhuǎn)換為浮點(diǎn)數(shù)
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函數(shù)
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' : '一般挽留客戶',
        '000' : '一般發(fā)展客戶',
    }
    result = d[label]
    return result

rfm['label'] = rfm[['R', 'F', 'M']].apply(lambda x: x-x.mean()).apply(rfm_func,axis=1)
image.png
rfm.groupby('label').sum()
image.png

從RFM分層可知昌简,大量用戶為重要保持客戶占业,但這是受到極值的影響,RFM劃分標(biāo)準(zhǔn)應(yīng)以業(yè)務(wù)為準(zhǔn)

  • 盡量用小部分用戶覆蓋大部分額度
  • 不用為了數(shù)據(jù)好看劃分等級(jí)
rfm.loc[rfm.label == '重要價(jià)值客戶', 'color'] = 'b'
rfm.loc[~(rfm.label == '重要價(jià)值客戶'), 'color'] = 'r'
rfm.plot.scatter('F', 'R', c = rfm.color)
image.png

4)用戶分層——新老客纯赎、活躍度

# 數(shù)據(jù)透視谦疾,user_id為索引,月為列址否,求每月消費(fèi)次數(shù)
pivoted_counts = df.pivot_table(index = 'user_id',
                               columns = 'month',
                                values = 'order_dt',
                               aggfunc = 'count').fillna(0)
pivoted_counts.head()
image.png
# 轉(zhuǎn)變維度餐蔬,有消費(fèi)記錄為1,沒(méi)有消費(fèi)記錄為0
df_purchase = pivoted_counts.applymap(lambda x: 1 if x > 0 else 0)
df_purchase.tail()
image.png
# 由于進(jìn)行數(shù)據(jù)透視佑附,將一些null值填充為0樊诺,而實(shí)際有可能該用戶當(dāng)月還沒(méi)有注冊(cè),
# 這樣會(huì)讓第一次消費(fèi)統(tǒng)計(jì)數(shù)據(jù)出錯(cuò)音同,因此定義一個(gè)函數(shù)來(lái)進(jìn)行處理
def active_status(data):
    status = []
    for i in range(18):
        
        #若本月沒(méi)有消費(fèi)
        if data[i] == 0:
            if len(status) > 0:
                if status[i-1] == 'unreg':
                    status.append('unreg')
                else:
                    status.append('unactive')
            else:
                status.append('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

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

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

若本月有消費(fèi)

  • 若是第一次消費(fèi)顿膨,則為新用戶
  • 若之前有消費(fèi),上個(gè)月為不活躍叽赊,則為回流
  • 若上個(gè)月未注冊(cè)恋沃,則為新用戶
  • 其他,為活躍用戶
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
# 把未注冊(cè)的記錄替換為空值必指,這樣count計(jì)算時(shí)不會(huì)被計(jì)算到
purchase_stats_ct = purchase_stats.replace('unreg',np.NaN).apply(lambda x:pd.value_counts(x))
purchase_stats_ct
image.png

可以發(fā)現(xiàn)活躍用戶在減少囊咏,非活躍用戶不斷增加

# T轉(zhuǎn)置,同時(shí)求出所有用戶占比
purchase_stats_ct.fillna(0).T.apply(lambda x:x/x.sum(),axis = 1) 
image.png
# 繪制面積圖
purchase_stats_ct.fillna(0).T.plot.area()
image.png

由上圖可知每月不同消費(fèi)狀態(tài)的人群變化情況

5)用戶購(gòu)買周期

# 計(jì)算兩個(gè)訂單的時(shí)間間隔
order_diff=grouped_user.apply(lambda x:x.order_dt-x.order_dt.shift())
order_diff.head(10)
image.png
order_diff.describe()
image.png
# 去除單元值并作圖
(order_diff/np.timedelta64(1,'D')).hist(bins=20)
image.png

可以發(fā)現(xiàn),用戶的購(gòu)買周期具有以下幾個(gè)特點(diǎn):

  • 訂單周期呈指數(shù)型分布
  • 用戶平均購(gòu)買周期是68天
  • 大部分用戶購(gòu)買周期低于100天

5梅割、復(fù)購(gòu)率和回購(gòu)率分析

  • 復(fù)購(gòu)率:自然月內(nèi)購(gòu)買兩次以上的用戶占比
  • 回購(gòu)率:某一時(shí)期內(nèi)曾經(jīng)購(gòu)買過(guò)的用戶再次購(gòu)買的占比
# 復(fù)購(gòu)率
pivoted_counts.head(10)
image.png
# 區(qū)分一次和一次以上的情況霜第,以便計(jì)算復(fù)購(gòu)率(大于1為1,等于1為0户辞,等于0為NaN)
purchase_r=pivoted_counts.applymap(lambda x:1 if x>1 else np.NaN if x==0 else 0)
purchase_r.head()
image.png
# 復(fù)購(gòu)人數(shù)/總消費(fèi)人數(shù)
(purchase_r.sum()/purchase_r.count()).plot(figsize=(10,4))
image.png

可以發(fā)現(xiàn)泌类,復(fù)購(gòu)率大體穩(wěn)定在20%左右,前三個(gè)月大量只購(gòu)買一次的新用戶的涌入底燎,導(dǎo)致復(fù)購(gòu)率較低

# 回購(gòu)率刃榨,知道本月是否有消費(fèi)記錄即可
df_purchase.head()
image.png
# 使用函數(shù)來(lái)定義回購(gòu)率,當(dāng)月已消費(fèi)的用戶下月也有消費(fèi)記錄的計(jì)入回購(gòu)
def purchase_back(data):
    status=[]
    """判斷每個(gè)月是否有回購(gòu)书蚪,根據(jù)上個(gè)月是否有購(gòu)買記錄進(jìn)行判斷喇澡,上個(gè)月有消費(fèi)本月沒(méi)有消費(fèi)就不是回購(gòu)"""
    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個(gè)月補(bǔ)充NaN
    """語(yǔ)句中的是 第一位與第二位相比 輸出結(jié)構(gòu)放第一位, 循環(huán)17次殊校,17/18的判斷結(jié)束后,輸出的status僅17個(gè)读存,需補(bǔ)上最后一個(gè)"""
    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.head()
image.png
# 求得回購(gòu)率
(purchase_b.sum()/purchase_b.count()).plot(figsize=(10,4))
image.png

可以發(fā)現(xiàn)絕大部分用戶購(gòu)買一次后不再購(gòu)買为流,老用戶回購(gòu)率在30%左右

四、總結(jié)

1让簿、cd網(wǎng)站在前三個(gè)月涌入了絕大多數(shù)的新用戶敬察,月訂單數(shù)量在11000左右,月消費(fèi)人數(shù)在8000到10000之間尔当,之后均回落至2000左右的水平
2莲祸、50%的用戶僅貢獻(xiàn)了15%的消費(fèi)額度,消費(fèi)排名前5000的用戶就貢獻(xiàn)了60%的消費(fèi)額椭迎,符合二八法則锐帜。同時(shí)該網(wǎng)站用戶平均購(gòu)買了7張cd,中位數(shù)只有3畜号,說(shuō)明有小部分用戶購(gòu)買了大量CD缴阎,同樣也符合二八法則
3、根據(jù)用戶首購(gòu)简软、末購(gòu)情況蛮拔,可以發(fā)現(xiàn)用戶的受次購(gòu)買集中分布在前三個(gè)月,且購(gòu)買一次后便不再購(gòu)買痹升,該部分用戶占比50%(符合2中提及的50%用戶僅貢獻(xiàn)15%的消費(fèi)額度)
4建炫、根據(jù)用戶分層RFM模型以及新老客、活躍度情況的分析疼蛾,大量用戶為重要保持客戶肛跌,絕大多數(shù)新用戶集中在前三個(gè)月,之后大部分轉(zhuǎn)為非活躍用戶
5、按用戶購(gòu)買周期分析惋砂,用戶平均購(gòu)買周期為68天妒挎,大部分用戶購(gòu)買周期集中在100天內(nèi)
6、從復(fù)購(gòu)率和回購(gòu)率的角度來(lái)看西饵,該cd網(wǎng)站的復(fù)購(gòu)率答題穩(wěn)定在20%左右酝掩,回購(gòu)率在30%左右

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市眷柔,隨后出現(xiàn)的幾起案子期虾,更是在濱河造成了極大的恐慌,老刑警劉巖驯嘱,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件镶苞,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡鞠评,警方通過(guò)查閱死者的電腦和手機(jī)茂蚓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)剃幌,“玉大人聋涨,你說(shuō)我怎么就攤上這事「合纾” “怎么了牍白?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)抖棘。 經(jīng)常有香客問(wèn)我茂腥,道長(zhǎng),這世上最難降的妖魔是什么切省? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任最岗,我火速辦了婚禮,結(jié)果婚禮上数尿,老公的妹妹穿的比我還像新娘仑性。我一直安慰自己,他們只是感情好右蹦,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布诊杆。 她就那樣靜靜地躺著,像睡著了一般何陆。 火紅的嫁衣襯著肌膚如雪晨汹。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,829評(píng)論 1 290
  • 那天贷盲,我揣著相機(jī)與錄音淘这,去河邊找鬼剥扣。 笑死,一個(gè)胖子當(dāng)著我的面吹牛铝穷,可吹牛的內(nèi)容都是我干的钠怯。 我是一名探鬼主播,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼曙聂,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼晦炊!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起宁脊,我...
    開(kāi)封第一講書(shū)人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤断国,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后榆苞,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體稳衬,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年坐漏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了薄疚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡仙畦,死狀恐怖输涕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情慨畸,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布衣式,位于F島的核電站寸士,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏碴卧。R本人自食惡果不足惜弱卡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望住册。 院中可真熱鬧婶博,春花似錦、人聲如沸荧飞。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)叹阔。三九已至挠轴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間耳幢,已是汗流浹背岸晦。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人启上。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓邢隧,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親冈在。 傳聞我的和親對(duì)象是個(gè)殘疾皇子倒慧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349