CD网站数据分析用户行为分析

阅读路线

项目介绍:该项目对国外某一CD网站的用户购买数据进行分析,主要围绕平台整体消费情况和用户行为展开分析叙述,通过分析该网站基本消费情况,找出高价值用户人群,及用户留存、活跃、流失等情况,为平台指定策略提供数据分析支持和建议。

代码展示
1.初始设置

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
plt.style.use('seaborn-colorblind')
plt.rcParams['font.sans-serif']=['SimHei'] 
plt.rcParams['axes.unicode_minus']=False

2.导入数据,查看信息

Column=['user_id','order_dt','order_products','order_amount']
df=pd.read_table('E:/CDNOW_master.txt',sep='\s+',names=Column)
df.info()

1.png

原始数据共有4个字段,共69659行,数据没有缺失值,下面是各字段含义:
user_id:用户id
order_dt:订单时间
order_products:订单购买产品数
order_amount:订单消费金额
以上,order_dt为整数类型,显然需要进行数据类型转化,而且为方便后续对月份的分析,需要增加一个新的字段month,表示订单的月份

3.整体消费情况


2.png

从上图可以得出:
订单金额:平均每笔订单的消费金额约36元,中位数约26元,标准差约36元,说明存在极值的干扰。
订单产品数:平均每笔订单购买产品数为2.4件,中位数为2件,75%的订单产品数为3件,说明大多数用户单笔订单都是2或3件,存在极值干扰。


3.png
group_month=df.groupby('month')
fig,axes=plt.subplots(2,2,figsize=(20,10))
axes0,axes1,axes2,axes3=axes.flatten()
# 每月销售金额
group_month.order_amount.agg('sum').plot(marker='o',ax=axes0)
axes0.set_title('每月消费金额')
axes0.set_ylabel('消费金额')
# 每月销售产品数
group_month.order_products.sum().plot(marker='o',ax=axes1)
axes1.set_title('每月销售产品数')
axes1.set_ylabel('销售产品数')
# 每月订单数
group_month.order_products.count().plot(marker='o',ax=axes2)
axes2.set_title('每月订单数')
axes2.set_ylabel('订单数')
group_month.user_id.unique().apply(lambda x:len(x)).plot(marker='o',ax=axes3)
axes3.set_title('每月客户数')
axes3.set_ylabel('客户数')
4.png

由上述图表可得,平台的销售金额、销售产品数和订单数都是比较高的,且都是在3月份左右出现峰值,单月销售金额最高达到40万美元、销售产品数最高达到2.7万件、订单数最高达到1.2万单、购买客户数在2月份左右就达到峰值9500人左右。但从第4个月开始,平台各项销售指标出现严重的下滑,顾客流失现象严重。

fig,axes=plt.subplots(1,2,figsize=(15,6))
axes0,axes1=axes.flatten()
# 每月客单价
group_month_pct=group_month.order_amount.sum()/group_month.user_id.unique().apply(lambda x:len(x))
group_month_pct.plot(marker='o',ax=axes0)
axes0.set_title('每月客单价')
axes0.set_ylabel('客单价')
# 每月件单价
group_month_up=group_month.order_amount.sum()/group_month.order_products.sum()
group_month_up.plot(ax=axes1,marker='o')
axes1.set_title('每月件单价')
axes1.set_ylabel('件单价')
5.png

从图中可以看出,前四月份的客单价稳步提升的,后几个月在46~57之间波动,前几个月客单价低可能和商家给的优惠政策相关。
件单价分析:前四月份,件单价相对较高,后几个月波动较大,尤其是在九月份和第二年的四月份。

group_user=df.groupby('user_id')
group_user_des=group_user[['order_amount','order_products','order_dt',]].agg({"order_amount":'sum','order_products':'sum','order_dt':'count'}).describe()
group_user_des.rename(columns={'order_dt':'消费次数','order_amount':'消费总金额','order_products':'产品购买数(件)'})
6.png

1、用户消费总金额:用户平均消费金额为106元,中位数为43元,标准差约为241,存在极值干扰;
2、用户消费次数:用户平均消费次数为3次,中位数为1次,标准差为4.7,同样,也存在着极值干扰;
3、用户产品购买数:用户平均购买产品数为7件,中位数为3件,标准差为16,同样也是有相当大的极值干扰。

fig,axes=plt.subplots(1,3,figsize=(16,4))
axes0,axes1,axes2=axes.flatten()
# 用户消费金额的分布情况
group_user.sum().query('order_amount<1000').order_amount.plot.hist(bins=20,ax=axes0)
axes0.set_title('用户消费金额的分布情况')
axes0.set_xlabel('消费金额')
axes0.set_ylabel('人数')
# 用户消费次数的分布情况
group_user.sum().query('order_products<100').order_products.plot.hist(bins=20,ax=axes1)
axes1.set_title('用户消费次数的分布情况')
axes1.set_xlabel('消费次数')
axes1.set_ylabel('人数')
# 用户购买产品数量的分布情况
group_user.count().query('order_dt<20').order_dt.plot.hist(bins=20,ax=axes2)
axes2.set_title('用户购买产品数量的分布情况')
axes2.set_xlabel('购买产品数量')
axes2.set_ylabel('人数')
7.png

从上图可以看出,用户购买金额普遍偏低,消费频次也是普遍偏低,当然这也符合销售数据的一般规律。

group_user.sum().query('order_amount<4000').plot.scatter(x='order_amount',y='order_products',title='用户消费金额与产品购买数量散点图',figsize=(6,4))
8.png

由上图可得,我们可以清楚的发现用户消费金额与产品购买数量之间存在一定的线性关系,当然,这也并不奇怪,因为该网站的产品单一,价格波动不大,由此产生了这样的线性关系。

group_user_cum=group_user.sum().sort_values('order_amount').apply(lambda x:x.cumsum()/x.sum())
group_user_cum.reset_index().order_amount.plot(figsize=(6,4))
plt.title('用户消费金额占比')
plt.xlabel('用户数量')
plt.ylabel('消费金额占比')
9.png

从上图可以明显的看出,该CD网站的用户消费金额存在着典型的“二八分布”,大约16%的头部用户贡献了60%的销售额,而超过60%的用户仅仅贡献了不到20%的销售额。

group_user=df.groupby('user_id')
fig,axes=plt.subplots(1,2,figsize=(12,4))
axes0,axes1=axes.flatten()
# 用户第一次购买的时间分布
group_user.order_dt.min().value_counts().plot(ax=axes0)
axes0.set_title('用户首购时间分布')
axes0.set_ylabel('人数')
# 用户最后一次购买的时间分布
group_user.order_dt.max().value_counts().plot(ax=axes1)
axes1.set_title('用户最后一次购买的时间分布')
axes1.set_ylabel('人数')
10.png

我们可以看出,大多数用户在前四个月就流失了,因此,也验证了此前提出的与首购的优惠有关的可能性。

group_user_diff=df.sort_values('order_dt').groupby('user_id').apply(lambda x:(x.order_dt-x.order_dt.shift())/np.timedelta64(1,'D'))
group_user_diff.describe()
11.png

我们可以看出,用户平均购买周期约为69天,中位数为31天,可以根据用户的购买周期对用户进行定期召回。

group_user_lifecycle=group_user.order_dt.apply(lambda x:x.max()-x.min())/np.timedelta64(1,'D')
# 用户生命周期为0天的用户占比
lifecycle_0=len(group_user_lifecycle[group_user_lifecycle==0])/len(df.user_id.unique())
lifecycle_not0=len(group_user_lifecycle[group_user_lifecycle>0])/len(df.user_id.unique())
values=[lifecycle_0,lifecycle_not0]
label=['用户只消费一次','用户消费不止一次']
fig = plt.figure(figsize=(8,8)) 
plt.pie(values,labels=label,autopct='%1.1f%%')
plt.title('用户消费次数占比')
plt.show()
12.png

我们再一次清楚地看到,大多数用户仅仅消费了一次,很有必要对用户进行定期召回。

rfm=group_user['order_products','order_amount'].sum()
rfm['R']=-(group_user.order_dt.max()-df.order_dt.max())/np.timedelta64(1,"D")
rfm.rename(columns={'order_products':'F','order_amount':'M'},inplace=True)
rfm=rfm[['R',"F",'M']]
def level_label(x):
    level=x.apply(lambda x:'1' if x> 0 else '0')
    model=level.R+level.F+level.M
    dic={
        "111":"重要价值客户",
        '101':'重要发展客户',
        "011":"重要维护客户",
        '001':'重要挽留客户',
        '001':'重要挽留客户',
        '110':'一般价值客户',
        '100':'一般发展客户',
        '010':'一般维持客户',
        '000':'一般挽留客户',
    }
    return dic[model]

rfm['label']=rfm.apply(lambda x:x-x.mean()).apply(level_label,axis=1)

fig,axes=plt.subplots(1,3,figsize=(14,4))
axes0,axes1,axes2=axes.flatten()
rfm_per=rfm.groupby('label').M.agg(['count','sum']).apply(lambda x :x/x.sum())
rfm_per['avg']=rfm_per['sum']/rfm_per['count']

rfm_per['count'].plot.bar(ax=axes0)
axes0.set_title('用户分层人数占比')
axes0.set_xlabel('人数占比')

rfm_per['sum'].plot.bar(ax=axes1)
axes1.set_title('用户分层消费金额占比')
axes1.set_xlabel('消费金额占比')

rfm_per['avg'].plot.bar(ax=axes2)
axes2.set_title('用户分层平均消费金额')
axes2.set_xlabel('平均消费金额')
13.png

从上图可以看出,接近60%的用户属于一般发展客户,这一类客户占比较大,但是仅仅贡献消费金额的17%左右,平均消费金额仅仅0.25万美元,在各类客户当中属于最低水平;第二大用户群是重要维护客户,人数占比接近20%,贡献的销售额达到63%左右,平均消费金额达3.3万元,这一类客户价值极高,对于这一类客户应该做好重点维护,防止用户流失,从而为平台创造更大的收入。

pivot_user=df.pivot_table(index='user_id',columns='month',values='order_amount',aggfunc='count').fillna(0)
def active_status(x):
    status=[]
    for i in range(len(x)):
        #若本月没有消费
        if x[i] ==0:
            if i!=0:
                if status[i-1]=='unreg':
                    status.append('unreg')
                else :status.append('unactive')
            else :status.append('unreg')
        #若本月消费了    
        elif x[i]!=0:   
            if i!=0:
                if status[i-1]=='unreg':
                    status.append('new')
                elif status[i-1]=='unactive':
                    status.append('return')
                else :status.append('active')
            else :status.append('new')   
    return pd.Series(status,index=x.index)
pivot_user_status=pivot_user.apply(active_status,axis=1)
pivot_user_status=pivot_user_status.apply(lambda x:x.value_counts()).fillna(0).T.drop('unreg',axis=1)
pivot_user_status.apply(lambda x:x/x.sum(),axis=1).plot.area()
plt.title('每月用户活动状态')
plt.ylabel('用户人数占比')
14.png

前三月份用户人数不断增高,新增用户数量和活跃用户数量都占较大比例,但后续无新用户注册,活跃用户数量下降最后趋于稳定水平,同时也有稳定的回流用户。

(pivot_user_status['return']/pivot_user_status['unactive'].shift()).plot()
plt.title('每月回流用户占比')
plt.ylabel('用户占比')
15.png

我们可以看到,四月份以后,用户回流率开始显著下降,并且稍有波动。

fig,axes=plt.subplots(1,2,figsize=(12,4))
axes0,axes1=axes.flatten()
# 用户每月复购率
repeated_purchase=pivot_user.applymap(lambda x:1 if x>1 else np.NaN if x==0 else 0)
repeated_purchase.apply(lambda x:x.sum()/x.count()).plot(ax=axes0)
axes0.set_title('每月复购率')
axes0.set_ylabel('复购率')

# 用户每月回购率
def buy_back_choose(x):
    mask=x>0
    label=[]
    for i in range(len(x)-1):
        if mask[i] and mask[i+1]:
            label.append(1)
        elif mask[i]:
            label.append(0)
        else:
            label.append(np.NaN)
    return pd.Series(label,index=x.index[:-1])

buy_back=pivot_user.apply(buy_back_choose,axis=1)
buy_back.apply(lambda x:x.sum()/x.count()).plot(ax=axes1)
axes1.set_title('每月回购率')
axes1.set_ylabel('回购率')
16.png

我们可以看到,前几个月,复购率较低,从四月份之后,复购率稳定在21%左右,而从每月回购率的角度来看,前几个月回购率依旧较低,但四月份之后,便在25%~37%之间上下波动。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,176评论 5 469
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,190评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,232评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,953评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,879评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,177评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,626评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,295评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,436评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,365评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,414评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,096评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,685评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,771评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,987评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,438评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,032评论 2 341

推荐阅读更多精彩内容