CD案例分析總結

本次案例的數據來源于CDNOW待诅,是美國的一家網上唱片公司,數據描述的是這家公司網站上的用戶消費記錄熊镣,分析目標旨在分析用戶消費行為卑雁,建立RFM模型,分析復購率绪囱、回購率等關鍵指標测蹲。數據字典如下:

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

數據集包含69659條記錄,共有4個字段鬼吵,時間范圍從19970101-19980630之間扣甲,下面是數據集整理統計描述:


整體描述.png

一、用戶消費趨勢分析(按月)

分別統計每月的消費總金額而柑、消費次數文捶、產品購買量、消費人數

grouped_month_info = grouped_month[['order_amount','user_id','order_products']].agg({'order_amount':sum, 'user_id': 'count', 'order_products':sum}).reset_index()
grouped_month_info.rename(columns = {'order_amount':'消費金額', 'user_id': '消費次數', 'order_products': '產品購買量'}, inplace=True)
grouped_month['user_id'].unique().map(len)
grouped_month_info['消費人次'] = grouped_month['user_id'].unique().map(len)

月產品購買量.png

由上圖可知媒咳,消費金額在前三個月達到最高峰粹排,后續(xù)消費較為穩(wěn)定,有輕微下降趨勢


月消費金額.png

由上圖可知涩澡,產品購買量在前三個月達到最高峰顽耳,后續(xù)消費較為穩(wěn)定,有輕微下降趨勢


月消費人次和消費次數.png

前三個月消費訂單人數在10000筆左右,后續(xù)月份的平均消費人數則在2500人射富,每月消費人數低于每月消費次數膝迎,但差異不大。

二胰耗、用戶個體消費分析

1限次、用戶消費金額,消費次數的描述統計

grouped_user=df.groupby('user_id').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

結果如下:
用戶平均購買了7張柴灯,但是中位值只有3卖漫,說明小部分用戶購買了大量貨物,用戶平均消費106元赠群,中位值有43羊始,判斷同上,這說明也有極值干擾查描。

2突委、用戶消費金額和消費次數的散點圖

用戶消費金額,消費次數.png

為排除極值干擾冬三,order_amount篩選<4000,由散點圖可知匀油,用戶消費金額與產品購買量幾乎成線性關系,購買的商品越多勾笆,消費金額就越大钧唐。

3、用戶消費金額和頻次的分布圖

grouped_user_sum_order_amount = grouped_user.sum().order_amount #每個用戶的金額
grouped_user_sum_order_amount_lst = [i for i in range(0,int(grouped_user_sum_order_amount.max())+50,50)]
grouped_user_sum_order_amount = pd.cut(grouped_user_sum_order_amount, bins=grouped_user_sum_order_amount_lst,labels = grouped_user_sum_order_amount_lst[1:])
用戶消費金額頻次.png

從直方圖可知匠襟,用戶消費金額,絕大部分呈現集中趨勢该园,小部分異常值干擾了判斷酸舍,可以使用過濾操作排除異常, 這里我們使用切比雪夫定理過濾掉異常值,因為切比雪夫定理說明里初,95%的數據都分布在5個標準差之內啃勉,剩下5%的極值就不要了。如下:

order_amount (mean = 106 ,std = 241) mean+5std = 1311

4双妨、用戶累計消費金額占比(百分之多少的用戶占了百分之多少的消費額)

# cumsum 是求累加值
user_cumsum=grouped_user.sum().sort_values('order_amount').apply(lambda x:x.cumsum()/x.sum())
累積消費金額曲線.png

按照用戶消費金額進行升序排序淮阐,由圖可以知道50%的用戶僅貢獻了11%的消費額度,而排名前5000的用戶就貢獻了60%的消費額度刁品。

三泣特、用戶消費行為

1、用戶第一次消費(首購)

grouped_user_min = grouped_user.min().order_dt.value_counts().reset_index().rename(columns={'index':'first_date'})
grouped_user_min['first_date'] =grouped_user_min['first_date'].astype(str)
首購分布.png

用戶第一次購買分布集中在前三個月挑随。其中状您,在2月9日到2月25日之間有劇烈的波動。

2、用戶最后一次消費

grouped_user_max = grouped_user.max().order_dt.value_counts().reset_index().rename(columns={'index':'last_date'})
grouped_user_max['last_date'] =grouped_user_max['last_date'].astype(str)
最后一次購買分布.png

上圖呈現斷崖式下跌很正常膏孟,可以理解為用戶流失比例基本一致眯分,一開始用戶迅猛增長數量比較多流失的也比較多,后面沒有用戶柒桑,用戶最后一次購買的分布比第一次分布廣弊决,大部分最后一次購買,集中在前三個月魁淳,說明很多用戶購買了一次后就不再進行購買飘诗。隨著時間的遞增,最后一次購買數量也在遞增先改,消費呈現流失上升的狀況(這也是正常疚察,隨著時間的增長,可能因為運營沒有跟上或者用戶忠誠度下降了)

3仇奶、新老客戶消費比

  • 多少用戶僅消費一次
#新老客消費比
# 得到第一次和最后yc次消費情況貌嫡,如果 min、max 日期相同该溯,說明只消費了一次
user_life=grouped_user.order_dt.agg(['min','max'])
# 統計只消費了一次的用戶
(user_life['min']==user_life['max']).value_counts()
消費了一次.png

結論得出大概有一半的用戶岛抄,只消費了一次

  • 每月新客占比
# 按照month、userid分組狈茉,第一次和最后一次消費日期
user_life_month=df.groupby(['month','user_id']).order_dt.agg(['min','max']).reset_index()
# 新增is_new字段夫椭,用于標記新用戶
user_life_month['is_new']=(user_life_month['min']==user_life_month['max'])
# 再次按month分組,計算新用戶占比
user_life_month_pct=user_life_month.groupby('month').is_new.apply(lambda x:x.value_counts()/x.count()).reset_index()
# level_1為True的作圖
user_life_month_pct[user_life_month_pct.level_1].plot(x='month',y='is_new')

新客占比.png

上圖看出1997年1月新用戶占比高達90%以上氯庆,后續(xù)有所下降蹭秋,并逐漸趨于平穩(wěn),1997年4月到1998年6月維持在81%左右堤撵,1998年6月以后無新用戶仁讨。

4、用戶分層

  • RFM模型
    R:最后一次消費距今天數实昨,F:消費總金額 洞豁,M:消費總產品數
    為得到最近一次消費,一般是計算 today 距離最近一次消費荒给,這里因為時間太久遠丈挟,就隨便用的max值,數值越大就越久遠志电,分子得到的是一些天數類似 545 days(因為是時間格式相減)曙咽,再除以一個單位,就不會有單位了溪北,只留下數值桐绒,如下:
# 重命名夺脾,也就是 R:最后一次消費距今天數
rfm['R']= -(rfm.order_dt - rfm.order_dt.max())/np.timedelta64(1,'D')
#  F:消費金額  M:消費頻次
rfm.rename(columns={'order_products':"F",'order_amount':'M'},inplace=True)
# RFM模型
def rfm_func(x):
    level=x.apply(lambda x:'1' if x>=0 else '0')
    # level 的類型是 series,index 是 R茉继、F咧叭、M
    #print(level)
    #print(level.index)
    label=level.R + level.F + level.M
    #print(label)
    d={
        # R 為1 表示離均值較遠即時間很久,F為1 表示 消費金額比較多烁竭,M 為1 表示消費頻次比較多菲茬,所以是重要價值客戶
        '111':'重要價值客戶',
        '011':'重要保持客戶',
        '101':'重要發(fā)展客戶',
        '001':'重要挽留客戶',
        '110':'一般價值客戶',
        '010':'一般保持客戶',
        '100':'一般發(fā)展客戶',
        '000':'一般挽留客戶',
    }
    result=d[label]
    return result

# 注意這里是要一行行的傳遞進來,所以 axis=1派撕,傳遞一行得到一個 111婉弹,然后匹配返回一個值
rfm['label']=rfm[['R','F','M']].apply(lambda x:x-x.mean()).apply(rfm_func,axis=1)
# 歸結為兩類方便得出客戶標簽
rfm.loc[rfm.label=='重要價值客戶','color']='重要價值客戶'
rfm.loc[~(rfm.label=='重要價值客戶'),'color']='非重要價值客戶'
客戶標簽分布.png

紫色部分是重要價值客戶,消費頻次較高终吼。

rfm.groupby('label').sum()
 M  F   R
label           
一般價值客戶  7181.28     650     36295.0
一般保持客戶  19937.45    1712    29448.0
一般發(fā)展客戶  438291.81   29346   6951815.0
一般挽留客戶  196971.23   13977   591108.0
重要價值客戶  167080.83   11121   358363.0
重要保持客戶  1592039.62  107789  517267.0
重要發(fā)展客戶  33028.40    1263    114482.0
重要挽留客戶  45785.01    2023    56636.0

從RFM 分層可知镀赌,大部分用戶是重要保持客戶,但是這是由于極值的影響际跪,所以 RFM 的劃分標準應該以業(yè)務為準商佛,也可以通過切比雪夫去除極值后求均值,并且 RFM 的各個劃分標準可以都不一樣.

  • 新姆打、老良姆、活躍、回流幔戏、流失
# 數據透視玛追, userid為索引,月為列闲延,求每月的消費次數痊剖,這里填充了
pivoted_counts=df.pivot_table(index='user_id',
                             columns='month',
                             values='order_dt',
                             aggfunc='count').fillna(0)
# 轉變一下消費,有消費為1垒玲,沒有消費為0
df_purchase=pivoted_counts.applymap(lambda x:1 if x>0 else 0)
df_purchase.tail()
# 這里由于進行數據透視邢笙,填充了一些 null 值為0,而實際可能用戶在當月根本就沒有注冊侍匙,
#這樣會誤導第一次消費數據的統計,所以寫一個函數來處理
# 上面填充了一些null值為0叮雳,而實際可能用戶在當月根本就沒有注冊想暗,這樣會誤導第一次消費數據的統計,所以寫一個函數來處理
def active_status(data):
    status=[]
    # 數據一共有18個月份帘不,每次輸入一行數據说莫,也就是一個user_id的信息,進行逐月判斷
    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')
    return status

關于active_status的說明:

return:回流 new:新客 unreg:未注冊 active:活躍
若本月沒有消費猜绣,這里只是和上個月判斷是否注冊,有一定的缺陷敬特,應該判斷是否存在就可以了

若之前有數據掰邢,是未注冊,則依舊為未注冊
若之前有數據擅羞,不是未注冊尸变,則為流失/不活躍
若之前沒有數據,為未注冊
若本月有消費

若是第一次消費减俏,則為新用戶
若之前有過消費召烂,上個月為不活躍,則為回流
若之前有過消費娃承,上個月為未注冊奏夫,則為新用戶
若之前有過消費,其他情況為活躍

purchase_stats=df_purchase.apply(lambda x: pd.Series(active_status(x),index=df_purchase.columns),axis=1)
purchase_stats.head()
# 這里把未注冊的替換為空值历筝,這樣 count 計算時不會計算到
# 得到每個月的用戶分布
purchase_stats_ct=purchase_stats.replace('unreg',np.NaN).apply(lambda x:pd.value_counts(x))
purchase_stats_ct
returnratee=purchase_stats_ct.apply(lambda x:x/x.sum(),axis=0)
purchase_stats_ct_info = purchase_stats_ct.fillna(0).T

用戶分層.png

前三個月有大量新用戶涌入酗昼,新用戶占比很高,而后面幾個月不活躍用戶占比非常高梳猪,普遍在90%以上麻削。活躍用戶春弥,持續(xù)消費的用戶呛哟,對應的是消費運營的質量∧渑妫回流用戶扫责,之前不消費,本月才消費逃呼,對應的是喚回運營鳖孤。不活躍用戶者娱,對應的是流失。

5苏揣、用戶購買周期(按訂單)

  • 用戶消費周期描述
# 用戶購買周期(按訂單)
# 計算相鄰兩個訂單的時間間隔黄鳍,shift 函數是對數據進行錯位,所有數據會往下平移一下腿准,所以可以
order_diff=grouped_user.apply(lambda x:x.order_dt-x.order_dt.shift())
order_diff.head(10)
購買周期.png

描述性統計:


統計.png

6弟跑、用戶生命周期(按第一次和最后一次消費)

  • 用戶生命周期描述


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


    生命周期1.png

    用戶平均生命周期134天灾前,但中位數僅0天。用戶的生命周期分布受只購買一次的用戶(用戶生命周期0天)影響比較嚴重孟辑,可以排除哎甲,得到:


    生命周期2.png

    用戶平均生命周期276天,中位數302天饲嗽。

7炭玫、復購率

復購率:自然月內,購買多次的用戶占比(即貌虾,購買了兩次以上)

# 區(qū)分一個吞加,和一個以上的情況,以便于計算復購率尽狠,大于1為1衔憨,等于0 為NaN,等于1為0
purchase_r=pivoted_counts.applymap(lambda x: 1 if x>1 else np.NaN if x==0 else 0)
purchase_r.head()
purchase_r_reshop = (purchase_r.sum()/purchase_r.count()).reset_index(name = 'reshop')
復購率.png

復購率穩(wěn)定在20%所有袄膏,前一個月因為有大量新用戶涌入践图,而這批用戶只購買了一次,所以導致復購率降低

8沉馆、回購率

回購率:曾經購買過的用戶在某一時期的再次購買的占比(可能是在三個月內)

# 需要使用函數來判斷是否回購:當月消費過的用戶下個月也消費了叫做回購码党,這個定義可以改變
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)
    # 第18個月補充NaN,因為沒有下個月的數據了
    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_backshop = purchase_b.sum()/purchase_b.count()
回購率.png

回購率穩(wěn)定在30%左右,前3個月因為有大量新用戶涌入缺猛,而這批用戶只購買了一次缨叫,所以導致回購率較低椭符。

四、小結

1耻姥、用戶消費趨勢(每月)方面销钝,前3個月有大量新用戶涌入,消費金額琐簇、消費訂單數蒸健、產品購買量均達到高峰,后續(xù)每月較為穩(wěn)定婉商。前3個月消費次數都在10000筆左右似忧,后續(xù)月份的平均2500;前3個月產品購買量達到20000甚至以上丈秩,后續(xù)月份平均7000盯捌;前3個月消費人數在8000-10000之間,后續(xù)月份平均2000不到蘑秽。

2饺著、用戶個體消費方面大概符合二八法則,小部分用戶購買了大量的CD肠牲,拉高了平均消費金額幼衰。用戶消費金額集中在0100元,有大約17000名用戶缀雳。用戶購買量集中在05個渡嚣,有大約16000名用戶。50%的用戶僅貢獻了15%的消費額度俏险,15%的用戶貢獻了60%的消費額度严拒。

3、用戶消費行為方面竖独,首購和最后一次購買的時間裤唠,集中在前三個月,說明很多用戶購買了一次后就不再進行購買莹痢。而且最后一次購買的用戶數量也在隨時間遞增种蘸,消費呈現流失上升的狀況。

4竞膳、從整體消費記錄來看航瞭,有一半的用戶,只消費了一次坦辟。從每月新用戶占比來看刊侯,1997年1月新用戶占比高達90%以上,后續(xù)有所下降锉走,1997年4月到1998年6月維持在81%左右滨彻,1998年6月以后無新用戶藕届。

5、從RFM模型來看亭饵,在8種客戶中休偶,重要保持客戶的消費頻次和消費金額最高,人數排在第二位辜羊;而一般發(fā)展客戶消費頻次和消費金額排第二位踏兜,人數卻是最多。

6八秃、從用戶分層情況來看帜慢,新用戶從第4月份以后沒有新增笙蒙;活躍用戶有所下降涌攻;回流用戶數量趨于穩(wěn)定墙歪,每月1000多。流失/不活躍用戶舍悯,數量非常多航棱,基本上每月都在20000以上。

7萌衬、用戶購買周期方面饮醇,平均購買周期是68天,最小值0天秕豫,最大值533天朴艰。絕大部分用戶的購買周期都低于100天。

8混移、用戶生命周期方面祠墅,由于只購買一次的用戶(生命周期為0天)占了接近一半,排除這部分用戶的影響之后歌径,用戶平均生命周期276天毁嗦,中位數302天。

9回铛、復購率和回購率方面狗准,復購率穩(wěn)定在20%左右,回購率穩(wěn)定在30%左右茵肃,前3個月因為有大量新用戶涌入腔长,而這批用戶只購買了一次,所以導致復購率和回購率都比較低验残。

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末捞附,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌鸟召,老刑警劉巖想鹰,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異药版,居然都是意外死亡,警方通過查閱死者的電腦和手機喻犁,發(fā)現死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門槽片,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人肢础,你說我怎么就攤上這事还栓。” “怎么了传轰?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵剩盒,是天一觀的道長。 經常有香客問我慨蛙,道長辽聊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任期贫,我火速辦了婚禮跟匆,結果婚禮上,老公的妹妹穿的比我還像新娘通砍。我一直安慰自己玛臂,他們只是感情好,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布封孙。 她就那樣靜靜地躺著迹冤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪虎忌。 梳的紋絲不亂的頭發(fā)上泡徙,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機與錄音呐籽,去河邊找鬼锋勺。 笑死,一個胖子當著我的面吹牛狡蝶,可吹牛的內容都是我干的庶橱。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼贪惹,長吁一口氣:“原來是場噩夢啊……” “哼苏章!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤枫绅,失蹤者是張志新(化名)和其女友劉穎泉孩,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體并淋,經...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡寓搬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了县耽。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片句喷。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖兔毙,靈堂內的尸體忽然破棺而出唾琼,到底是詐尸還是另有隱情,我是刑警寧澤澎剥,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布锡溯,位于F島的核電站,受9級特大地震影響哑姚,放射性物質發(fā)生泄漏祭饭。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一蜻懦、第九天 我趴在偏房一處隱蔽的房頂上張望甜癞。 院中可真熱鬧,春花似錦宛乃、人聲如沸悠咱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽析既。三九已至,卻和暖如春谆奥,著一層夾襖步出監(jiān)牢的瞬間眼坏,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工酸些, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留宰译,地道東北人。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓魄懂,卻偏偏與公主長得像沿侈,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子市栗,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345