练习1总结

作者: bf3780a4db09 | 来源:发表于2019-02-08 18:52 被阅读9次

    这周主要学习了matplotlib和seaborn两个可视化库的基本操作,以及一个实战项目,实战项目已经结合了可视化内容,主要就是总结这个实战项目。
    所用的数据是一份关于用户消费的数据,


    image.png

    包括四个地段:
    user_id:用户ID
    order_dt:消费时间
    order_products:购买的产品数量
    order_amount:消费金额
    在正式开始分析之前,需要对数据做一些处理:

    • 是否存在缺失值
      Python
    df.isnull().sum()
    

    SQL中没有找到特别好的方法,只能一列一列看是否存在null

    SELECT count(*) FROM aa.cdnow_master
    where user_id is null;
    

    返回Python的结果


    image.png

    关于如何处理缺失值问题,现在还没怎么实战过,看到的比较多的就是删除或者填充,填充这一块有很多方法【简单的平均值、中位数、前向、后向,复杂的就涉及到一些机器学习模型了,后面结合例子再来看吧】
    这个数据集不存在缺失值,就不考虑这一块了。

    • 数据类型
      这里主要是处理日期格式,原来的日期格式是int类型,修改为%Y%m%d类型,考虑到后面要按照月份来分析,添加一列month。
      Python
    df.info()  #
    df['order_dt'] = pd.to_datetime(df['order_dt'],format='%Y%m%d') #修改日期的数据类型
    df['month']=df['order_dt'].values.astype('datetime64[M]')  #将日期精确到月份
    

    注:astype修改数据类型,type查看数据类型,dtype数组元素的类型
    SQL的话,可以在导入之前就设定好字段类型为date,或者用SQL语句修改

    alter table aa.cdnow_master modify column order_dt date #修改order_dt字段为日期类型
    alter table aa.cdnow_master add column mon_th date not null;#新增一个精确到月的日期字段
    update aa.cdnow_master set mon_th= date_format(order_dt,'%Y-%m-01') #更新新列
    

    注意:在用sql处理的时候,不需要给表设定user_id为主键,否则一些重复的user_id就被自动过滤了。
    简单的处理完原始数据,看一下数据的大体情况

    image.png
    从上面的数据可以看出
    • 大部分订单只消费了少量产品(平均为2.4),有一定极值干扰(最大值和最小值差异较大)。最小值是1,中位数也才2,最大值为99,平均值却只有2.4,其实没有怎么体现出极值对平均值的影响,猜测是数据量相对较大的原因。
    • 用户的消费金额比较稳定,平均消费35.89,中位数是25.98,有一定极值干扰。和产品数有相同的现象。
      主要从四个角度来分析:

    1、用户消费趋势的分析(按月份)

    指标1是每月的消费总金额
    指标2是每月的消费次数
    指标3是每月的产品购买量
    指标4是每月的消费人数

    指标1 每月的消费总金额

    Python

    grouped_month = df.groupby('month')
    order_month_amount = grouped_month['order_amount'].sum()  #每月的消费总额
    order_month_amount.sort_values(ascending=False)
    

    SQL

    SELECT mon_th,sum(order_amount) as total
    FROM aa.cdnow_master
    group by mon_th
    order by total desc
    

    返回Python结果


    image.png

    可视化

    import matplotlib.pyplot as plt
    plt.rcParams['figure.figsize']=(10,6)#设置画布大小
    plt.style.use('ggplot')  #设置图形显示风格为ggplot类型
    order_month_amount.plot(marker='*') #折线图
    #或者plt.plot(order_month_amount,marker='*') 
    

    返回结果


    image.png

    结论:

    • 由上图可知,消费金额在前三个月达到最高峰,四月份有大幅下降,此后消费额较为稳定,仍然有轻微的下降趋势。
    • 每年的3月份有一次上涨,4月份下降

    指标2是每月的消费订单量

    方法与消费金额类似
    Python

    month_count = grouped_month['user_id'].count()
    month_count
    

    SQL

    SELECT mon_th,count(user_id)
    FROM aa.cdnow_master
    group by mon_th
    order by mon_th 
    

    结果


    image.png

    可视化

    month_count.plot(marker='o',mec='r',mfc='w')
    

    结果


    image.png

    结论:

    • 前三个月消费订单数在10000单左右,与每月的消费金额一致,四月份的订单量下滑较大,后续月份的平均消费在2500笔左右。

    指标3是每月的产品购买量

    Python

    grouped_month['order_products'].sum().plot()
    

    SQL查询

    SELECT mon_th,sum(order_products)
    FROM aa.cdnow_master
    group by mon_th
    order by mon_th
    

    返回Python结果


    image.png

    结论:

    • 前三个月是产品销售高峰在23000左右,四月份下滑幅度较大,后续消费较稳定,相较于前三个月,呈下降趋势。

    指标4是每月的消费人数

    计算消费人数时注意一个用户会多次下单的问题【去重】
    Python

    grouped_month['user_id'].apply(lambda g: len(g.drop_duplicates())).plot()
    #或者用分组来去重
    df.groupby(['month','user_id']).count().reset_index().groupby('month')['order_dt'].count().plot()
    

    SQL查询

    SELECT mon_th,count(distinct user_id)
    FROM aa.cdnow_master
    group by mon_th
    order by mon_th
    

    返回结果


    image.png

    结论:

    • 每月消费人数低于每月消费订单量【消费人数<=消费订单量】,但差异不大【大部分用户每月只下一次单】
    • 前三个月每月的消费人数在8000到10000之间,四月份下滑到3000左右,后续月份,平均消费人数在2000人不到
      指标1到指标3都可以用数据透视表来进行计算
    df.pivot_table(index='month',values=['user_id','order_products','order_amount'],
                  aggfunc={'user_id':'count','order_products':np.sum,'order_amount':np.sum})
    

    结果


    image.png

    除了上面四个指标,还可以看一下

    每月用户平均消费金额趋势

    Python

    sum_1.div(sum_2,level='month').plot()  #每月用户平均消费金额
    plt.yticks(range(35,90,20))
    

    SQL查询

    select  mon_th,totalamount/totaluser
    from(
    SELECT mon_th,
    sum(order_amount) as totalamount,
    count(distinct user_id) as totaluser
    FROM aa.cdnow_master
    group by mon_th) as t
    

    结果


    image.png

    结论:

    • 除了前三个月略微低一些,后续月份的用户平均消费金额较为稳定。【??第四个月的用户量、消费金额、消费产品数降幅较大,平均消费金额倒是不算低】

    每月用户平均下单量的趋势

    Python

    sum_3 = grouped_month['user_id'].count() #每月订单总量
    sum_3.div(sum_2,level='month')
    

    SQL查询

    select  mon_th,totalorder/totaluser
    from(
    SELECT mon_th,
    count(user_id) as totalorder,
    count(distinct user_id) as totaluser
    FROM aa.cdnow_master
    group by mon_th) as t
    
    image.png

    结论:

    • 每月用户平均下单一次,较稳定。

    每月用户平均消费产品数的趋势

    Python

    sum_4 = grouped_month['order_products'].sum()
    sum_4.div(sum_2,level='month') #每月用户平均消费产品数量
    

    SQL查询

    select  mon_th,totalproducts/totaluser
    from(
    SELECT mon_th,
    sum(order_products) as totalproducts,
    count(distinct user_id) as totaluser
    FROM aa.cdnow_master
    group by mon_th) as t
    

    返回结果


    image.png

    结论:

    • 每月用户的产品平均购买量保持在2到3个
      注:从平均值的角度去分析一些指标,似乎覆盖掉了一些点,比如:四月份的消费金额、消费产品数、下单量都大幅下降,它的用户平均指标还变高了一些。
      一般来说,消费金额、消费产品数、下单量、用户量这四个指标是相互关联的,比如:用户量越多,一般下单量越多,用pairplot验证一下
    month_pair=df.pivot_table(index='month',values=['user_id','order_products','order_amount'],
                  aggfunc={'user_id':'count','order_products':np.sum,'order_amount':np.sum})
    month_pair.rename(columns={'user_id':'ordertotal','order_products':'productstotal','order_amount':'amounttotal'},inplace=True)
    month_pair['usertotal']=df.groupby('month')['user_id'].apply(lambda x:len(x.drop_duplicates()))
    import seaborn as sns
    sns.pairplot(month_pair)
    plt.savefig('C:/Users/lenovo/Desktop/1.jpeg')
    

    返回结果


    1.jpeg

    结论:

    • 四个指标两两之间有线性关系的趋势
    • 包含三个离群点【前三个月的数据】
      关于线性关系,以用户量和消费金额为例
    sns.lmplot(data=month_pair, x='usertotal',y='amounttotal')
    sns.lmplot(data=month_pair, x='usertotal',y='amounttotal',robust=True)#去除离群点
    

    返回第一个结果


    image.png

    返回第二个结果


    image.png

    处理离群点:看第一个结果,似乎三个离群点把拟合直线的斜率变得更平缓一些,不了解数据的背景时代,但从用户量和消费金额来说,这3个离群点似乎不能算异常值;用程序验证一下,设置函数的参数robust=True去除离群点的影响,两者差异不大【在拟合时并没有删除3个点】,自己每次看到离群点第一个反应就是删除,也算是给自己做个提醒吧。

    2、用户个体消费分析

    维度1用户消费金额、消费产品量的描述统计
    维度2用户消费金额和消费的散点图
    维度3用户消费金额的分布图
    维度4用户消费产品量的分布图
    维度5用户累计消费金额占比(百分之多少的用户占了百分之多少的消费额)【算好符合28规则之后,可以看看这些个用户的消费特点(看他们的消费金额、消费次数的描述统计以及相应的分布图)】

    维度1用户消费金额、消费产品量的描述统计

    金额和产品数的统计概况

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

    返回结果


    image.png

    结论:

    • 用户平均购买了7张CD,但是中位数只有3,最大值为1033,标准差接近17【说明存在极值干扰,小部分用户购买了大量的CD】
    • 用户平均消费106元,中位数只有43,上四分位数为106,最大值为13990,判断同上,存在极值干扰

    维度2用户消费金额和消费的散点图

    grouped_user.sum().plot.scatter(x='order_products',y='order_amount')
    

    返回结果


    image.png

    结论:

    • 数据集中在左下角,大部分用户购买的CD数在300张以内,消费金额在4000以下
    • 购买的产品数量与消费金额有线性关系的趋势【如:同一种产品,这种关系代表了产品单价】

    维度3用户消费金额的分布图

    查看用户消费产品数和消费金额的分布趋势,此处对数据做一个简单清洗,借鉴切比雪夫定理:所有数据中,至少有24/25(或96%)的数据位于平均数5个标准差范围内。因此,消费产品数选取[0,7.12+5*16.98],即[0,92],消费金额选取[0,1310.73]的数据。
    Python

    grouped_user.sum().query('order_amount<=1310.73')['order_amount'].plot.hist(bins=100) #
    
    

    SQL查询语句

    select  user_id,totalamount
    from(
    SELECT user_id,
    sum(order_amount) as totalamount
    FROM aa.cdnow_master
    group by user_id) as t
    where totalamount<=1310.73
    

    返回


    image.png

    结论:

    • 从直方图可知,用户消费金额,绝大部分呈现集中趋势,小部分异常值干扰了判断

    维度4用户消费产品量的分布图

    Python

    grouped_user.sum().query('order_products<=92')['order_products'].plot.hist(bins=40)
    

    SQL查询语句

    select  user_id,totalproducts
    from(
    SELECT user_id,
    sum(order_products) as totalproducts
    FROM aa.cdnow_master
    group by user_id) as t
    where totalproducts<=92
    

    返回


    image.png

    结论:

    • 大部分用户购买的cd数量较少,少部分用户购入了大量cd

    维度5用户累计消费金额占比

    Python

    amount_cumsum = grouped_user.sum().sort_values(by=['order_amount'],ascending=False).apply(lambda x:x.cumsum()/x.sum())['order_amount']
    amount_cumsum.reset_index()['order_amount'].plot()
    

    SQL查询语句

    select t1.user_id,(@csum:=@csum+t1.totalamount) as csumamount
    from
    (select user_id,sum(order_amount)/(select sum(order_amount) from aa.cdnow_master) as totalamount 
    from aa.cdnow_master
    group by user_id
    order by totalamount desc) as t1,(select @csum:=0) as t2;
    

    返回Python结果


    image.png

    结论:

    • 消费排名前5000的用户,已经贡献了约70%的消费额度
    • 消费排名靠后的50%用户,仅贡献了约15%的消费额度
    • 用户消费金额基本呈28原则的趋势

    查看一下消费排名前5000的用户的消费金额和消费产品数的情况

    grouped_user_2 = grouped_user.sum().sort_values(by=['order_amount'],ascending=False).apply(lambda x:x.cumsum()/x.sum())
    grouped_user_80 = grouped_user.sum().loc[grouped_user_2.iloc[:5000].index]
    grouped_user_80.describe() #描述统计
    

    返回


    image.png

    由上表可知,数据结果相对集中,仍然存在极值影响。
    消费产品数

    df2 = df.set_index('user_id')
    df2_80 = df2.loc[grouped_user_2.iloc[:5000].index]
    product_80 = df2_80.groupby('month').sum()['order_products']
    product_total = df.groupby('month').sum()['order_products']
    product_80.div(product_total)
    

    SQL查询语句

    select mon_th,
    sum(if(t2.user_id is null,0,t1.order_products))/sum(t1.order_products) as monthproducts
    from aa.cdnow_master as t1
    left join
    (
    select user_id
    from aa.cdnow_master
    group by user_id
    order by sum(order_amount) desc
    limit 5000) as t2
    on t1.user_id=t2.user_id
    group by t1.mon_th
    order by t1.mon_th
    

    注:由于计算精度原因,Python和SQL中的第五千个用户分别为用户20464和9654,所以两个结果有一点点不一样
    返回


    image.png

    可视化

    df2_80.groupby('month').sum()['order_products'].plot()
    

    返回


    image.png

    结论:

    • 由上表可知,除了前三个月,这5000名用户贡献了每个月80%以上的产品消费量,【前三个月用户大量增加,所以这些用户的产品消费量贡献在50%左右,后续用户不再增加,由这部分用户承担起大部分消费量,是不是可以说,这部分用户包含大量活跃用户?】
    • 这5000名用户的每月消费量散点图,趋势与原始散点图差异不大
    • 每个三月都会有一次上涨
      消费金额
    amount_80 = df2_80.groupby('month').sum()['order_amount']
    amount_total = df.groupby('month').sum()['order_amount']
    amount_80.div(amount_total)
    df2_80.groupby('month').sum()['order_amount'].plot()
    

    SQL查询语句

    select mon_th,
    sum(if(t2.user_id is null,0,t1.order_amount))/sum(t1.order_amount) as monthamount
    from aa.cdnow_master as t1
    left join
    (
    select user_id
    from aa.cdnow_master
    group by user_id
    order by sum(order_amount) desc
    limit 5000) as t2
    on t1.user_id=t2.user_id
    group by t1.mon_th
    order by t1.mon_th;
    

    注:由于计算精度原因,Python和SQL中的第五千个用户分别为用户20464和9654,所以两个结果有一点点不一样
    返回


    image.png
    image.png

    结论与消费产品数的结论一致

    3、用户消费行为

    维度1用户第一次消费(首购)
    维度2用户最后一次消费
    维度3多少用户仅消费了一次

    • 每月新客占比
      维度4用户分层
    • RFM()
    • 新、老、活跃、回流、流失
      维度5用户购买周期(按订单)
    • 用户消费周期描述
    • 用户消费周期分布
      维度6用户生命周期(按第一次和最后一次消费)
    • 用户生命周期描述
    • 用户生命周期分布

    维度1用户第一次消费(首购)

    Python

    grouped_user.min()['order_dt'].value_counts().plot()
    

    SQL查询

    select firstorder, count(*) from
    (select user_id,min(order_dt) as firstorder 
    from aa.cdnow_master
    group by user_id) as t
    group by firstorder
    

    返回


    image.png

    结论:

    • 用户第一次购买分布,集中在前三个月
    • 存在多个峰值,波动较大,其中,2月13号至2月27号有一次剧烈的波动,先大幅度增加再大幅度下降

    维度2用户最后一次消费

    Python

    grouped_user.max()['order_dt'].value_counts().plot()
    

    SQL查询语句

    select firstorder, count(*) from
    (select user_id,max(order_dt) as firstorder 
    from aa.cdnow_master
    group by user_id) as t
    group by firstorder
    order by count(*) desc
    

    返回


    image.png

    结论:

    • 用户最后一次购买的分布比第一次分布广
    • 大部分最后一次购买集中在前三个月,说明有很多用户购买了一次后不再购买
    • 随着时间的递增,最后一次购买数也在下降,消费呈现流失上升的情况

    维度3多少用户仅消费了一次

    Python

    user_life = grouped_user['order_dt'].agg(['min','max'])
    (user_life['min']==user_life['max']).value_counts()
    

    SQL查询语句

    select count(*) from
    (select user_id
    from aa.cdnow_master
    group by user_id
    having count(*) = 1) as t
    

    返回

    image.png
    注:上面Python方法得出仅消费一次的用户为12054,但是按照SQL的方法得到11908,原因在于Python方法的时间只精确到天,有一部分用户同一天消费了两次,比如id为2的用户,在1月12号消费了两次,Python方法将他作为只消费了一次的用户。
    因此按SQL的思路修改Python
    user_life_2 = grouped_user.count()
    (user_life_2['order_dt']==1).value_counts()
    

    返回:


    image.png

    结论:

    • 约50%的用户仅消费了一次

    维度4用户分层

    RFM(最近一次消费、消费次数【此处用消费产品数】、消费金额)

    Python

    rfm = df.pivot_table(index='user_id',values=['order_dt','order_products','order_amount'],aggfunc={'order_dt':'max',
                                                              'order_products':'sum','order_amount':'sum'})
    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模型
    def rfm_func(x):
        level=x.apply(lambda x: '1' if x>=0 else '0')
        label = level.R+level.F+level.M
        d={
            '111':'重要价值客户',#消费时间较远,消费频次和消费金额够
            '011':'重要保持客户',  #最重要的客户,消费时间近,消费频次和消费金额够
            '101':'重要发展客户',#消费时间远,消费金额够,消费频次不够
            '001':'重要挽留客户',#消费时间近,消费频次不够,消费金额够
            '110':'一般价值客户',#消费时间远,消费频次够,消费金额不够
            '010':'一般保持客户',#消费时间近,消费频次够,消费金额不够
            '100':'一般发展客户',#消费时间远,消费频次和消费金额不够
            '000':'一般发展客户'#消费时间近,消费频次和消费金额都不够
        }
        return d[label]
    
    rfm['label'] = rfm[['R','F','M']].apply(lambda x:x-x.mean()).apply(rfm_func,axis=1)  # 
    计算每个字段与平均值的差距,根据差值进行分层
    rfm.head()
    

    SQL查询

    create table test4 (select user_id,max(order_dt) as R,sum(order_products) as F,sum(order_amount) as M
    from aa.cdnow_master
    group by user_id);
    alter table test4 add RR varchar(40) not Null;
    update test4,(select * from (select user_id,datediff((select max(R) from test4),R) as R from test4) as t5) as t6
    set test4.RR=t6.R
    where test4.user_id=t6.user_id;
    select label,count(*)
    FROM
    (select *,
    (case
    WHEN RFM='111' THEN '重要价值客户'
    WHEN RFM='011' THEN '重要保持客户'  
    WHEN RFM='101' THEN '重要发展客户'
    WHEN RFM='001' THEN '重要挽留客户'
    WHEN RFM='110' THEN '一般价值客户'
    WHEN RFM='010' THEN '一般保持客户'
    WHEN RFM='100' THEN '一般发展客户'
    WHEN RFM='000' THEN '一般发展客户'
    end) as label
    from
    (select *,
    CONCAT(if((RR-(select AVG(RR) from test4))>=0,1,0),
           if((F-(select AVG(F) from test4))>=0,1,0),
           if((M-(select AVG(M) from test4))>=0,1,0)) as RFM
    from test4) as t4) as t5
    group by label;
    

    返回结果中,已为每个用户打好标签


    image.png

    可视化
    简单点划分为两种

    rfm.loc[rfm['label']=='重要价值客户','color']='g' 
    rfm.loc[~(rfm['label']=='重要价值客户'),'color']='r'
    rfm.plot.scatter('F','R',c=rfm['color'])
    

    返回


    image.png

    注:plot.scatter()中的参数c,只能填颜色名称或者数字,不能填c=rfm['label']会报错【c of shape (23570,) not acceptable as a color sequence for x with size 23570, y with size 23570】
    按照原分层

    plt.rcParams['font.sans-serif']=['SimHei']  #用来正常显示中文标签
    plt.rcParams['axes.unicode_minus']=False  #用来正常显示负号 
    pie_1= rfm['label'].value_counts()
    plt.figure(figsize=(8,9))
    pie_1.plot.pie(autopct='%1.1f%%',explode=[0.05,0,0,0,0,0,0],pctdistance = 0.9,labeldistance = 1.1)
    

    返回


    image.png

    结论:

    • 由饼图可知,大部分的用户为一般发展客户,其次是重要保持客户,剩余用户层次占比均较小
    新用户【第一次消费】、活跃【持续在消费】、回流【隔了一段时间再次消费】、流失【不活跃,一段时间未消费】

    Python

    pivoted_counts = df.pivot_table(index='user_id',columns='month',values='order_dt',aggfunc='count').fillna(0) #每个用户每月的消费次数
    #这边只看用户每个月有没有消费过,消费次数这边不考虑
    df_purchase=pivoted_counts.applymap(lambda x:1 if x>0 else 0) #1代表本月消费,0代表未消费
    def active_status(data): #data是df_purchase的一行
        status=[]
        for i in range(18): #一共有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
    purchase_stats=df_purchase.apply(active_status,axis=1)#得到用户分层结果
    purchase_stats_ct=purchase_stats.replace({'unreg':np.NaN}).apply(lambda x:x.value_counts()) #用NaN替代unreg,以便后续计算不包含这些数据,未注册不考虑
    purchase_stats_ct.fillna(0).T.plot.area()#为了便于画图,将缺失值补齐
    

    这个的SQL没写出来
    返回

    image.png
    表格形式【每月各层用户占比】
    purchase_stats_ct.fillna(0).T.apply(lambda x:x/x.sum(),axis=1)  # 只要首购了,这个用户就会被纳入分析范围
    

    返回


    image.png

    此外,还可以计算每月的回流率

    purchase_return = purchase_stats_ct.fillna(0).T[['return','unactive']]
    purchase_return['return'].div(purchase_return['unactive'].shift(1)) #回流率一直都不太高
    

    SQL查询?
    返回


    image.png

    结论:

    • 新用户集中在前三个月,后续每月新用户接近0
    • 前三个月有一定数量的活跃用户,后续不活跃用户越来越多,表明消费运营质量不高,用户在不断流失
    • 回流率一直都不高,表明唤回运营效果不佳

    维度5用户购买周期(按订单)

    用户消费周期描述
    order_diff = df.groupby('user_id').apply(lambda x: x['order_dt']-x['order_dt'].shift()) #用户每笔订单的时间间隔
    order_diff.describe()  #不计算空值
    

    SQL查询

    select t1.user_id,
    @difft:=if(@id=user_id,DATEDIFF(order_dt,@pre),null) as dit,
    @pre:=order_dt,
    @id:=user_id
    from aa.cdnow_master as t1,
    (select @pre:=0,@id:=null) as t2
    ORDER BY user_id,order_dt
    

    返回


    image.png

    结论:

    • 用户的平均消费周期为68天,最大值为533天,存在部分极值
    用户消费周期分布
    sns.distplot((order_diff/np.timedelta64(1,'D')).dropna(),bins=20).set_xlim(0,600)
    

    返回


    image.png

    结论:

    • 订单周期呈指数分布
    • 绝大部分用户的购买周期都低于100天

    维度6用户生命周期(按第一次和最后一次消费)

    用户生命周期描述和分布

    Python

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

    SQL查询

    select user_id,DATEDIFF(MAX(order_dt),MIN(order_dt)) as userlife
    from aa.cdnow_master
    GROUP BY user_id
    

    返回


    image.png

    结论:

    • 用户平均消费134天,用户生命周期受只购买一次的用户影响比较厉害,用户生命周期的中位数为0,这50%的用户仅消费了一次
      排除仅消费了一次的用户,再次查看用户生命周期的分布
    sns.distplot(user_life[user_life>0],bins=40).set_xlim(0,600)
    

    返回


    image.png

    结论:

    • 这部分用户的生命周期不太稳定,分布较分散,暂时无法得到确切的周期分布
      第一次消费到第二次消费的时间间隔分布,可以写一下
    import heapq
    def user_func(x):
        if len(x)>1:
            return (heapq.nsmallest(2,x)[1]-heapq.nsmallest(2,x)[0])/np.timedelta64(1,'D')
        else:
            return None
    #user_fugou = grouped_user.count()[grouped_user.count()['order_dt']>1]
    grouped_user_2 = df.groupby('user_id')
    user_fugou_2 = grouped_user_2['order_dt'].apply(user_func )
    user_fugou_2.describe()
    user_fugou_2.plot.hist(bins=100)
    

    返回


    image.png
    image.png

    结论:

    • 用户复购时间集中在左下角,复购用户中大部分会在50天内第二次购买
    • 用户复购的平均时间间隔为108天,中位数为54天,最大值为533天,受部分极值影响

    复购率和回购率

    复购率

    Python

    purchase_r = pivoted_counts.applymap(lambda x: 1 if x>1 else np.NaN if x==0 else 0)#1表示本月复购了【购买次数大于1】,0表示本月只消费了一次,NaN表示本月未消费
    ((purchase_r.sum())/purchase_r.count()).plot(figsize=(10,4))
    

    SQL查询

    select mon_th ,
    sum(if(ordertimes>1,1,0))/count(*) as f1
    from
    (select user_id,mon_th,count(*) as ordertimes
    from aa.cdnow_master
    GROUP BY user_id,mon_th) as t
    GROUP BY mon_th
    ORDER BY mon_th
    

    返回


    image.png

    结论:

    • 复购率稳定在20%左右
    • 前三个月相对复购率较低

    回购率

    Python

    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) #填充最后一个月
        return status
    purchase_b = df_purchase.apply(purchase_back,axis=1)
    (purchase_b.sum()/purchase_b.count()).plot(figsize=(10,4))
    

    SQL查询

    select t1.mon_th,COUNT(DISTINCT t1.user_id) as totaluser,COUNT(t2.mon_th) as huser,
    COUNT(t2.mon_th)/COUNT(DISTINCT t1.user_id) as h1
    from
    (select user_id,mon_th
    from aa.cdnow_master
    GROUP BY user_id,mon_th) as t1
    LEFT JOIN
    (select user_id,mon_th
    from aa.cdnow_master
    GROUP BY user_id,mon_th) as t2
    on t1.user_id=t2.user_id
    and t1.mon_th = DATE_SUB(t2.mon_th,INTERVAL 1 month)
    GROUP BY t1.mon_th
    
    

    返回


    image.png

    结论:

    • 回购率稳定在30%左右
    • 4月份回购率涨幅较大,原因在于四月份用户量下滑

    相关文章

      网友评论

        本文标题:练习1总结

        本文链接:https://www.haomeiwen.com/subject/vjkusqtx.html