数据分析项目-用户消费行为分析

目录

导入及分析

第一部分:数据清洗

导包

数据加载&分析数据

数据清洗

第二部分:按月数据分析

分析方向:用户、订单、消费趋势 

消费趋势的分析

1. 每月的消费总金额

2. 每月的消费次数

3. 每月的产品购买量

4. 每月的消费人数(去重)

5. 将上述趋势分析用透视表展示(pivot_table)

第三部分:用户个体消费数据分析

1. 用户消费金额和消费次数的描述统计

2.用户消费金额和消费次数的散点图

3. 用户消费金额的分布图(二八法则)

4. 用户消费次数的分布图(二八法则)

5. 用户累计消费金额的占比(百分之多少的用户占了百分之多少的消费额)

第四部分:用户消费行为分析

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

2. 用户最后一次消费

3. 新老客户的消费比

4. 用户的购买周期

5. 用户分层(使用透视表)

5.1. 用户分层二:RFM 

5.2. 用户分层三:求和

5.3. 用户分层四:计数

5.4. 用户分层五:给不同层次客户用颜色区分设置 

5.5. 用户分层六:用户生命周期 

5.6. 用户分层七:用户购买周期(按订单)

6. 复购率和回购率的分析


 

导入及分析

项目名称:CD用户消费行为分析

项目概述:本项目主要利用Numpy,Pandas,matplotlib等三个工具进行数据的处理,来分析用户消费行为。数据来源与CDNow网站的用户购买明细。

分析步骤:

第一部分:数据清洗

    1. 数据类型的转换
    2. 空值处理
    3. 异常值处理

第二部分:按月数据分析

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

第三部分:用户个体消费数据分析

    1. 用户消费金额和消费次数的描述统计
    2. 用户消费金额和消费次数的散点图
    3. 用户消费金额的分布图
    4. 用户消费次数的分布图
    5. 用户累计消费金额的占比

第四部分:用户消费行为分析

    1. 用户第一次消费时间
    2. 用户最后一次消费时间
    3. 新老客户消费比
    4. 用户分层
    5. 用户购买周期
    6. 用户生命周期

第一部分:数据清洗

导包

#导入需要的包
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from datetime import  datetime

数据加载&分析数据

字段含义:

        user_id:用户ID

        order_dt:购买日期

        order_product:购买产品的数量

        order_amount:购买金额

消费行业或者是电商行业一般是通过订单数、订单额、购买日期,用户ID这四个字段来分析的,基本上这四个字段就能缑进行很丰富的分析。

# 因为原始数据中不包含表头,在这里定义好赋值
columns=['user_id','order_dt','order_products','order_amount']
# 参数 sep='\s+',用于匹配任意空白符
df=pd.read_csv('./data/CDNOW_master.txt',names=columns,sep='\s+')
print(df.head())
print(df.info())

输出结果

  user_id  order_dt  order_products  order_amount
0        1  19970101               1         11.77
1        2  19970112               1         12.00
2        2  19970112               5         77.00
3        3  19970102               2         20.76
4        3  19970330               2         20.76

RangeIndex: 69659 entries, 0 to 69658
Data columns (total 4 columns):
 #   Column          Non-Null Count  Dtype  
---  ------          --------------  -----  
 0   user_id         69659 non-null  int64  
 1   order_dt        69659 non-null  int64  
 2   order_products  69659 non-null  int64  
 3   order_amount    69659 non-null  float64
dtypes: float64(1), int64(3)
memory usage: 2.1 MB
None

Process finished with exit code 0

分析:

1.数据完整,没有空数据

2.order_dt是int类型,需要将其转换成时间类型

3.用户可能在同一天内重复购买(如:ID为2的顾客在1月12日这一天内购买了两次)

4.因为后面要按月分析,需要添加一列month

数据清洗

#数据清洗
df=date1.copy()
# format='%Y%m%d' 这里要指明格式,否则可能出错
df['order_dt']=pd.to_datetime(df['order_dt'],format='%Y%m%d')
# 增加一列 month
df['month']=df['order_dt'].values.astype('datetime64[M]')
print(df.head())

输出结果

   user_id   order_dt  order_products  order_amount      month
0        1 1997-01-01               1         11.77 1997-01-01
1        2 1997-01-12               1         12.00 1997-01-01
2        2 1997-01-12               5         77.00 1997-01-01
3        3 1997-01-02               2         20.76 1997-01-01
4        3 1997-03-30               2         20.76 1997-03-01

Process finished with exit code 0

分析:

describe()是描述统计:

            user_id  order_products  order_amount
count  69659.000000    69659.000000  69659.000000
mean   11470.854592        2.410040     35.893648
std     6819.904848        2.333924     36.281942
min        1.000000        1.000000      0.000000
25%     5506.000000        1.000000     14.490000
50%    11410.000000        2.000000     25.980000
75%    17273.000000        3.000000     43.700000
max    23570.000000       99.000000   1286.010000

Process finished with exit code 0

分析 

1. 大部分的订单只消费了少量的商品(平均2.4),有一定的极值干扰

2. 用户的消费金额比较稳定,平均消费在35.8元,中位数在25.9元,有一定的极值干扰。

3. 用户平均每笔订单购买2.4个商品,标准差在2.3,稍具波动性。中位数2个商品,75分位数3个商品, 说明绝大部分订单的购买量都不多。最大值在99个,数字比较高。购买金额的情况差不多,大部分 订单集中在小额

4. 一般而言,消费类的数据分布都是长尾形。大部分用户都是小额,然而小部分用户贡献了收入的大头, 俗称二八。

第二部分:按月数据分析

分析方向:用户、订单、消费趋势 

消费趋势的分析

# 查看一下df的列,方便操作
print(df.columns)

输出结果

Index(['user_id', 'order_dt', 'order_products', 'order_amount', 'month'], dtype='object')

1. 每月的消费总金额

#每月消费总金额
# 根据 month分组统计购买金额总和
order_amt_mon=df.groupby('month')['order_amount'].sum()
print(order_amt_mon.head())

 输出结果

month
1997-01-01    299060.17
1997-02-01    379590.03
1997-03-01    393155.27
1997-04-01    142824.49
1997-05-01    107933.30
Name: order_amount, dtype: float64

Process finished with exit code 0

绘图

#绘图
order_amt_mon.plot(c='red')
plt.show()

数据分析项目-用户消费行为分析_第1张图片

 分析:

可以看到,97年1,2,3月销量很高,每月平局约3.6万,后期销量趋于平稳,每月在1万左右波动

2. 每月的消费次数

#2. 每月的消费次数
order_amt_count=df.groupby('month')['user_id'].count()
#绘图
order_amt_count.plot(c='orange')
plt.show()

数据分析项目-用户消费行为分析_第2张图片

 分析:

前三个月平均消费订单在1万左右,后续月份趋于平稳,约在2500单每月

3. 每月的产品购买量

#3. 每月的产品购买量
order_products_sum=df.groupby('month')['order_products'].sum()
#绘图
order_products_sum.plot(c='b')
plt.show()

数据分析项目-用户消费行为分析_第3张图片

分析:

前3个月产品购买数量平均在24000左右,后期下降趋于平稳,约6000每月。原因猜想:

    1.用户层面,早期用户中有异常值;

    2. 公司层面,在搞促销等。因为只有销售数据,所以暂时无法判断具体原因。

4. 每月的消费人数(去重)

 每月的消费人数(去重)去重的原因:一个人可能在一个月内多次消费 

nunique表示统计去重后的个数

#4. 每月的消费人数(去重)去重的原因:一个人可能在一个月内多次消费
user_id_count=df.groupby('month')['user_id'].nunique()
user_id_count.plot(c='g')
plt.show()

数据分析项目-用户消费行为分析_第4张图片

分析:

每个月的消费人数小于每月的消费次数,但是区别不大。前3个月月均消费人数在9000左右,后续月均2000不到,一样是前期消费人多,后期平稳的趋势。

5. 将上述趋势分析用透视表展示(pivot_table)

#5. 将上述趋势分析用透视表展示(pivot_table)
df_pivot_table=df.pivot_table(index='month',
               values=['user_id',  'order_products', 'order_amount'],
               aggfunc={'user_id':'count','order_amount':'sum','order_products':'sum'})
print(df_pivot_table.head())

输出结果

           order_amount  order_products  user_id
month                                            
1997-01-01     299060.17           19416     8928
1997-02-01     379590.03           24921    11272
1997-03-01     393155.27           26159    11598
1997-04-01     142824.49            9729     3781
1997-05-01     107933.30            7275     2895

Process finished with exit code 0

分析:(解决一个需求可能会有很多种方法,具体看哪个更方便,更简单)

     数据透视表是更简单的方法,有了透视表,用里面的数据绘图也是狠方便的。

第三部分:用户个体消费数据分析

上面是通过维度月,来看总体趋势。下面对个体进行分析,看消费能力如何。 大致分为以下五个方向:

1. 用户消费金额和消费次数的描述统计;

2. 用户消费金额和消费次数的散点图;

3. 用户消费金额的分布图(二八法则);

4. 用户消费次数的分布图;

5. 用户累计消费金额的占比(百分之多少的用户占了百分之多少的消费额)

1. 用户消费金额和消费次数的描述统计

#1. 用户消费金额和消费次数的描述统计
df.groupby('user_id')['order_amount'].sum() #每一个用户消费的总金额
df.groupby('user_id').count()['order_dt'] #每一个用户消费的总金额
group_user=df.groupby('user_id')
print(group_user.sum().describe())

输出结果

       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

Process finished with exit code 0

分析:

1. 从用户角度看,每位用户平均购买7件商品,最多的用户买了1033件。

2. 用户平均消费额(客单价)100元,标准差是240,结合分位数和最大值看,平均值和75分位接近。

结论:肯定存在小部分高额消费用户,小部分的用户占了消费的大头,符合二八法则。

2.用户消费金额和消费次数的散点图

#2.用户消费金额和消费次数的散点图
user_amount_sum=df.groupby('user_id')['order_amount'].sum() #每一个用户消费的总金额
user_product_sum=df.groupby('user_id')['order_products'].sum() #每一个用户消费的总次数
plt.scatter(user_product_sum,user_amount_sum)
plt.show()
#方法2
group_user.sum().query('order_amount<4000').plot(kind='scatter',x='order_amount',y='order_products')
plt.show()

绘制图形

数据分析项目-用户消费行为分析_第5张图片

分析:

  通过绘制用户的散点图,用户比较健康而且规律性很强。因为这是CD网站的销售数据,商品比较单一,金额和商品质量的关系 也呈线性,没几个离群点。

3. 用户消费金额的分布图(二八法则)

#3. 用户消费金额的分布图(二八法则)
group_user.sum().query('order_amount<=1000')['order_amount'].plot(kind='hist',bins=20)
plt.show()

数据分析项目-用户消费行为分析_第6张图片

 分析:

1. 从直方图可知,大部分用户的消费能力确实不高,绝大部分集中在很低的消费档次。高消费用户在图上几乎看不到。这也确实 符合消费行为的行业规律。

2. 虽然有极值干扰了我们的数据,但是大部分用户还是集中在比较低的消费档次。

4. 用户消费次数的分布图(二八法则)

#4. 用户消费次数的分布图(二八法则)
group_user.sum().query('order_products<100')['order_products'].plot(kind='hist',bins=40)
plt.show()

数据分析项目-用户消费行为分析_第7张图片

5. 用户累计消费金额的占比(百分之多少的用户占了百分之多少的消费额)

# cumsum() 滚动累加求和
user_cumsum=(group_user.sum().sort_values('order_amount').cumsum()) / (2500315.63)
print(user_cumsum)

输出结果

        order_products  order_amount
user_id                              
10175      3.999495e-07      0.000000
4559       7.998990e-07      0.000000
1948       1.199849e-06      0.000000
925        1.599798e-06      0.000000
10798      1.999748e-06      0.000000
...                 ...           ...
7931       6.599847e-02      0.985405
19339      6.614965e-02      0.988025
7983       6.636402e-02      0.990814
14048      6.677717e-02      0.994404
7592       6.714392e-02      1.000000

[23570 rows x 2 columns]

Process finished with exit code 0

绘图

#绘图
user_cumsum.reset_index().order_amount.plot()
plt.show()

数据分析项目-用户消费行为分析_第8张图片

 分析:

按用户消费金额进行升序排序,由图可知50%的用户仅贡献了15%的销售额。而排名前5000的用户就贡献了60%的消费额

也就是说,只要维护好这5000个客户,就可以完成业绩KPI的60%,如果能把5000个用户运营的更好就可以占比70%-80%甚至更高。

第四部分:用户消费行为分析

用户第一次消费(首购)

在很多行业中首购是一个很重要的维度,它和渠道信息息息相关,尤其针对客单价比较高客户留存率比较低的行业,第一次客户从哪里来可以拓展出很多运营方式。

用户最后一次消费

新老客户消费比

多少客户仅消费了一次   每月新客占比

用户分层

 RFM   新、老、活跃、流失

 用户购买周期(按订单)

用户消费周期描述   用户消费周期分布

用户生命周期(按第一次&最后一次消费)

 用户生命周期描述   用户生命周期分布

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

求月份的最小值,即用户消费行为中的第一次消费时间 

#求月份的最小值,即用户消费行为中的第一次消费时间
group_user=df.groupby('user_id')
min_month=group_user['month'].min().value_counts()
print(min_month)

通过统计结果发现:所有用户第一次消费都集中在前3个月   df['user_id'].unique().size---查看用户总数

[23570 rows x 2 columns]
1997-02-01    8476
1997-01-01    7846
1997-03-01    7248
Name: month, dtype: int64

Process finished with exit code 0

2. 用户最后一次消费

#求月份的最大值,即用户消费行为中的最后消费时间
max_month=group_user['month'].max().value_counts()
print(max_month)

输出结果

Name: month, dtype: int64
1997-02-01    4912
1997-03-01    4478
1997-01-01    4192
1998-06-01    1506
1998-05-01    1042
1998-03-01     993
1998-04-01     769
1997-04-01     677
1997-12-01     620
1997-11-01     609
1998-02-01     550
1998-01-01     514
1997-06-01     499
1997-07-01     493
1997-05-01     480
1997-10-01     455
1997-09-01     397
1997-08-01     384
Name: month, dtype: int64

消费者最后一天绘图

#消费者最后一天绘图
group_user['order_dt'].max().value_counts().plot()
plt.show()

数据分析项目-用户消费行为分析_第9张图片

将第一次消费与最后一次消费做分析

cha=group_user['order_dt'].agg(['min','max'])
print(cha)
              min        max
user_id                      
1       1997-01-01 1997-01-01
2       1997-01-12 1997-01-12
3       1997-01-02 1998-05-28
4       1997-01-01 1997-12-12
5       1997-01-01 1998-01-03
...            ...        ...
23566   1997-03-25 1997-03-25
23567   1997-03-25 1997-03-25
23568   1997-03-25 1997-04-22
23569   1997-03-25 1997-03-25
23570   1997-03-25 1997-03-26

[23570 rows x 2 columns]

Process finished with exit code 0

 分析:

观察用户最后一次购买时间发现,用户最后一次消费比第一次消费分布广,大部分最后一次消费集中在前三个月

说明很多客户购买一次后就不再购买。随着时间的增长,最后一次购买数也在递增,消费呈现流失上升的情况,用户忠诚度在慢慢下降。

3. 新老客户的消费比

  • 消费一次为新用户
  • 消费多次为老用户
  • 判定:如果用户第一次消费时间和最后一次消费时间一样,则该用户只消费了一次
  • group_user['order_dt'].agg(['min','max'])#agg对分组后的结果进行多种指定聚合
#3. 新老客户的消费比
user_life=group_user['order_dt'].agg(['min','max'])
print(user_life.head())
               min        max
user_id                      
1       1997-01-01 1997-01-01
2       1997-01-12 1997-01-12
3       1997-01-02 1998-05-28
4       1997-01-01 1997-12-12
5       1997-01-01 1998-01-03

Process finished with exit code 0

分析: 

user_id为1的用户第一次消费时间和最后一次消费时间相同,说明他只消费了一次

4. 用户的购买周期

#4. 用户的购买周期
print((user_life['min']==user_life['max']).value_counts())

输出结果

True     12054
False    11516
dtype: int64

分析

可以看到,有一半的用户只消费了一次

5. 用户分层(使用透视表)

rfm = df.pivot_table(index='user_id',
                   values=['order_products','order_amount','order_dt'],
                   aggfunc={'order_products':'sum','order_amount':'sum','order_dt':'max'})

print(rfm.head())

 # order_products--求消费产品总数、order_amount---求消费总金额、order_dt--求最近一次消费时间
         order_amount   order_dt  order_products
user_id                                         
1               11.77 1997-01-01               1
2               89.00 1997-01-12               6
3              156.46 1998-05-28              16
4              100.50 1997-12-12               7
5              385.61 1998-01-03              29

Process finished with exit code 0
  • rfm 距今天数 增加一列 
  • -(rfm.order_dt - rfm.order_dt.max())结果为时间类型,将时间格式转化为整数或者浮点数的形式,
  • # 可以除以单位‘D’,也可以用astype转化 
#rfm 距今天数 增加一列
#-(rfm.order_dt - rfm.order_dt.max())结果为时间类型,将时间格式转化为整数或者浮点数的形式,
# 可以除以单位‘D’,也可以用astype转化
rfm['R']=-(rfm['order_dt']-rfm['order_dt'].max())/np.timedelta64(1,'D')
rfm.rename(columns={'order_products':'F','order_amount':'M'},inplace=True)
print(rfm.head())

输出结果

              M   order_dt   F      R
user_id                              
1         11.77 1997-01-01   1  545.0
2         89.00 1997-01-12   6  534.0
3        156.46 1998-05-28  16   33.0
4        100.50 1997-12-12   7  200.0
5        385.61 1998-01-03  29  178.0

分析:

R表示客户最近一次交易的时间间隔,M表示客户在最近一段时间内交易的金额。

F表示客户在最近一段时间内交易的次数。 F值越大,表示客户交易越频繁,反之则表示客户交易不够活跃。

M表示客户在最近一段时间内交易的金额。 M值越大,表示客户价值越高,反之则表示客户价值越低。

5.1. 用户分层二:RFM 

def rfm_func(x):
    level=x.apply(lambda x : '1' if x>=0 else '0')
    label=level.R+level.F+level.M
    dict={
        '111':'重要价值客户',
        '011':'重要保持客户',
        '101':'重要挽留客户',
        '001':'重要发展客户',
        '110':'一般价值客户',
        '010':'一般保持客户',
        '100':'一般挽留客户',
        '000':'一般发展客户'
    }
    result = dict[label]
    return result
 # 用户分层,这里使用平均数
rfm['label'] = rfm[['R','F','M']].apply(lambda x : x - x.mean()).apply(rfm_func,axis=1)
print(rfm.head())

输出结果

              M   order_dt   F      R   label
user_id                                      
1         11.77 1997-01-01   1  545.0  一般挽留客户
2         89.00 1997-01-12   6  534.0  一般挽留客户
3        156.46 1998-05-28  16   33.0  重要保持客户
4        100.50 1997-12-12   7  200.0  一般发展客户
5        385.61 1998-01-03  29  178.0  重要保持客户

5.2. 用户分层三:求和

#5. 用户分层三:求和
label_sum=rfm.groupby('label').sum()
print(label_sum)
                 M       F          R
label                                
一般价值客户     7181.28     650    36295.0
一般保持客户    19937.45    1712    29448.0
一般发展客户   196971.23   13977   591108.0
一般挽留客户   438291.81   29346  6951815.0
重要价值客户   167080.83   11121   358363.0
重要保持客户  1592039.62  107789   517267.0
重要发展客户    45785.01    2023    56636.0
重要挽留客户    33028.40    1263   114482.0

Process finished with exit code 0

分析:

M表示不同层次客户累计消费金额,重要保持客户最高

5.3. 用户分层四:计数

#5. 用户分层四:计数
label_count=rfm.groupby('label').count()
print(label_count)

分析:

不同层次用户的消费人数,之前重要保持客户的累计消费金额最高,这里人数排第2,但与一般挽留用户人数差距比较大

5.4. 用户分层五:给不同层次客户用颜色区分设置 

rfm.loc[rfm.label == '重要价值客户','color'] = 'g'
# ~:表示求非
rfm.loc[~(rfm.label == '重要价值客户'),'color'] = 'r'
rfm.plot('F','R',kind='scatter',c=rfm.color)
plt.show()

 数据分析项目-用户消费行为分析_第10张图片

 分析:

1. 从RFM分层可知,大部分用户为重要保持客户,但是这是由于极值的影响,所以RFM的划分应该尽量以业务为准。 尽量用小部分的用户覆盖大部分的额度,不能为了数据好看划分等级。

2. RFM是人工使用象限法把数据划分为几个立方体,立方体对应相应的标签,我们可以把标签运用到业务层面上。 比如重要保持客户贡献金额最多159203.62,我们如何与业务方配合把数据提高或者维护;而重要发展客户 和重要挽留客户他们有一段时间没消费了,我们如何把他们拉回来。

5.5. 用户分层六:用户生命周期 

pivoted_counts = df.pivot_table(index='user_id',
                                columns='month',
                              values='order_dt',
                              aggfunc='count',
                                fill_value=0)
print(pivoted_counts.head())
month    1997-01-01  1997-02-01  1997-03-01  ...  1998-04-01  1998-05-01  1998-06-01
user_id                                      ...                                    
1                 1           0           0  ...           0           0           0
2                 2           0           0  ...           0           0           0
3                 1           0           1  ...           0           1           0
4                 2           0           0  ...           0           0           0
5                 2           1           0  ...           0           0           0

[5 rows x 18 columns]

Process finished with exit code 0

分析:

用户每个月的消费次数,对于生命周期的划分只需要知道用户本月是否消费,消费次数在这里并不重要,需要将模型进行简化

注:使用数据透视表时,要明确获得什么结果。

# 简化
df_purchase = pivoted_counts.applymap(lambda x: 1 if x>0 else 0)
print(df_purchase.head())
month    1997-01-01  1997-02-01  1997-03-01  ...  1998-04-01  1998-05-01  1998-06-01
user_id                                      ...                                    
1                 1           0           0  ...           0           0           0
2                 1           0           0  ...           0           0           0
3                 1           0           1  ...           0           1           0
4                 1           0           0  ...           0           0           0
5                 1           1           0  ...           0           0           0

[5 rows x 18 columns]

分析:

对于尾部数据,user_id 2w+的数据是有一些问题的,因为从实际业务场景来说,一月二月他们都没有注册,三月份才是第一次消费。这里需要进行判断将第一次消费作为生命周期的起始,不能从一月份开始就粗略的计算。

一下算法为固定算法 

# 用户生命周期状态变化

def active_status(data):

    ur = 'unreg'    #未注册
    ua = 'unactive' #不活跃
    n = 'new'       #新用户
    a = 'active'    #活跃
    r = 'return'    #回流用户:上个月不活跃,这个月活跃
    status = []
    for i in range(18):
        #若本月没有消费
        if data[i] == 0:
            if len(status) > 0:
                if n not in status:
                    status.append(ur)
                else:
                    status.append(ua)
            else:
                status.append(ur)

        #若本月消费
        else:
            if len(status) == 0:
                status.append(n)
            else:
                if n not in status:
                    status.append(n)
                elif status[-1] == ua:
                    status.append(r)
                else:
                    status.append(a)
    # 不能直接返回 status,否则会失去表头    ---重点
    return pd.Series(status, index = df_purchase.columns)

pivoted_status = df_purchase.apply(active_status,axis = 1)

pivoted_status.head()

输出结果

month   1997-01-01 1997-02-01 1997-03-01  ... 1998-04-01 1998-05-01 1998-06-01
user_id                                   ...                                 
1              new   unactive   unactive  ...   unactive   unactive   unactive
2              new   unactive   unactive  ...   unactive   unactive   unactive
3              new   unactive     return  ...   unactive     return   unactive
4              new   unactive   unactive  ...   unactive   unactive   unactive
5              new     active   unactive  ...   unactive   unactive   unactive

[5 rows x 18 columns]

Process finished with exit code 0

每月不同活跃用户的计数

#每月不同活跃用户的计数
purchase_status_ct=pivoted_status.replace('unreg',np.NaN).apply(lambda x: pd.value_counts(x))
print(purchase_status_ct)

输出结果:统计每个月客户活跃度的汇总

5 rows x 18 columns]
month     1997-01-01  1997-02-01  ...  1998-05-01  1998-06-01
active           NaN      1157.0  ...       459.0       446.0
new           7846.0      8476.0  ...         NaN         NaN
return           NaN         NaN  ...      1029.0      1060.0
unactive         NaN      6689.0  ...     22082.0     22064.0
purchase_status_ct.fillna(0,inplace=True)
# 浮点数转换为整数
purchase_status_ct.astype(np.int)
# 绘面积图 (purchase_status_ct要求一下转置矩阵)
purchase_status_ct.T.plot(kind='area')
plt.show()

数据分析项目-用户消费行为分析_第11张图片

每月不同活跃用户占比

消费用户构成:活跃+新增+回流

#每月不同活跃用户占比
Fdf=purchase_status_ct.T.apply(lambda x:x/x.sum(),axis=1)
print(Fdf.head())

 输出结果

             active       new    return  unactive
month                                             
1997-01-01  0.000000  1.000000  0.000000  0.000000
1997-02-01  0.070886  0.519299  0.000000  0.409815
1997-03-01  0.071319  0.307510  0.025244  0.595927
1997-04-01  0.075223  0.000000  0.044506  0.880272
1997-05-01  0.036148  0.000000  0.057785  0.906067

 分析

由上表可以看到每月用户的消费状态变化。

1. 活跃用户,持续消费用户对应的是---消费运营质量

2. 回流用户(上月不消费本月消费)对应的是---唤回运营情况;

3. 不活跃的用户对应的是---用户流失情况。

得出分析:流失用户增加,回流客户正在减少

5.6. 用户分层七:用户购买周期(按订单)

# 将用户分组后,每个用户的订单购买时间进行错位相减  shift():下一行减上一行的值
order_diff=group_user.apply(lambda x:x.order_dt-x.order_dt.shift())
print(order_diff.head())

 输出结果

user_id   
1        0       NaT
2        1       NaT
         2    0 days
3        3       NaT
         4   87 days
Name: order_dt, dtype: timedelta64[ns]

Process finished with exit code 0

分析

1. 可以看到:user_id 1为空值,说明用户只购买过一个订单

2. user_id 2 的用户第一笔订单与第二笔订单在同一天购买

用户消费周期分布

#用户消费周期分布
(order_diff/np.timedelta64(1,'D')).hist(bins=20)
plt.show()

 数据分析项目-用户消费行为分析_第12张图片

 

 分析

订单周期呈指数分布,用户的平均购买周期是68天,绝大部分用户的购买周期都低于100天。

用户生命周期(第一笔订单时间 & 最后一笔订单时间)

user_life=group_user['order_dt'].agg(['min','max'])
print(user_life.head())

输出结果

               min        max
user_id                      
1       1997-01-01 1997-01-01
2       1997-01-12 1997-01-12
3       1997-01-02 1998-05-28
4       1997-01-01 1997-12-12
5       1997-01-01 1998-01-03

Process finished with exit code 0

相隔天数

user_life['life_period']=user_life['max']-user_life['min']
print(user_life.head())

得出结果

               min        max life_period
user_id                                  
1       1997-01-01 1997-01-01      0 days
2       1997-01-12 1997-01-12      0 days
3       1997-01-02 1998-05-28    511 days
4       1997-01-01 1997-12-12    345 days
5       1997-01-01 1998-01-03    367 days

Process finished with exit code 0

描述一下

print(user_life['life_period'].describe())

输出结果

count                          23570
mean     134 days 20:55:36.987696224
std      180 days 13:46:43.039788104
min                  0 days 00:00:00
25%                  0 days 00:00:00
50%                  0 days 00:00:00
75%                294 days 00:00:00
max                544 days 00:00:00
Name: life_period, dtype: object

Process finished with exit code 0

分析

可以看到,数据偏移较大,中位数是0天,意味着超过50%的用户生命周期是0天,即只购买了1次。

(user_life['life_period'] / np.timedelta64(1,'D')).plot(kind='hist',bins=40)
plt.show()

数据分析项目-用户消费行为分析_第13张图片

 分析:

可以看出,用户生命周期受只购买一次的用户影响比较大(因此可以排除生命周期为0天的用户再观察)

# 用户生命周期大于0天的分布图
cond=(user_life['life_period'] / np.timedelta64(1,'D'))
cond[cond>0].hist(bins=40)
plt.show()

数据分析项目-用户消费行为分析_第14张图片

分析

1. 有不少用户生命周期靠拢在0天,部分质量差的用户虽然消费了两次,但是仍然无法持续, 用户首次消费30天以内应该尽量引导;

2. 少部分用户集中在50-300天,属于普通型的生命周期;

3. 高质量用户的生命周期,集中在400天以后,这属于忠诚用户。

6. 复购率和回购率的分析

复购率:自然月内,购买多次的用户占比

回购率:曾经购买过的用户在某一时期内的再次购买占比

applymap()针对DataFrame里的所有数据。使用lambda函数,因为设计了多个结果,所以要用两个if else

user_id                                      ...                                    
1               0.0         NaN         NaN  ...         NaN         NaN         NaN
2               1.0         NaN         NaN  ...         NaN         NaN         NaN
3               0.0         NaN         0.0  ...         NaN         0.0         NaN
4               1.0         NaN         NaN  ...         NaN         NaN         NaN
5               1.0         0.0         NaN  ...         NaN         NaN         NaN

[5 rows x 18 columns]

Process finished with exit code 0

复购率

(purchase_r.sum()/purchase_r.count()).plot(figsize=(10,4))
plt.show()

数据分析项目-用户消费行为分析_第15张图片

 分析

1. 用sum和count相除即可计算出复购率。这两个函数都会忽略掉NaN,而NaN是没有消费的用户,count不论是0或1都会统计, 所以是总的消费用户数。而sum求和计算了消费两次及以上的用户。这里比较巧妙的用了替代法计算复购率。sql中也可以用。

2. 图上可以看出复购率在早期,因为大量新用户加入的关系,新客的复购率并不高,譬如1月新客们的复购率只有6%左右。 而在后期,这时的用户都是大浪淘沙剩下的老客户,复购率比较稳定,在20%左右。单看新客和老客,复购率有三倍左右的差距。

回购率:回购率是某一个时间窗口内消费的用户,在下个时间窗口仍旧消费的占比。

# 消费金额进行透视

pivoted_amount = df.pivot_table(index='user_id',
                                columns='month',
                                values='order_amount',
                                aggfunc='mean')
pivoted_amount.fillna(0,inplace=True)
columns_month = df['month'].sort_values().astype('str').unique()
pivoted_amount.columns = columns_month

# pivoted_amount.head()
print(pivoted_amount.head())
         1997-01-01  1997-02-01  1997-03-01  ...  1998-04-01  1998-05-01  1998-06-01
user_id                                      ...                                    
1             11.77         0.0        0.00  ...         0.0        0.00         0.0
2             44.50         0.0        0.00  ...         0.0        0.00         0.0
3             20.76         0.0       20.76  ...         0.0       16.99         0.0
4             29.53         0.0        0.00  ...         0.0        0.00         0.0
5             21.65        38.9        0.00  ...         0.0        0.00         0.0

[5 rows x 18 columns]

Process finished with exit code 0
pivoted_purchase = pivoted_amount.applymap(lambda x : 1 if x>0 else 0)
print(pivoted_purchase.head())

输出结果

         1997-01-01  1997-02-01  1997-03-01  ...  1998-04-01  1998-05-01  1998-06-01
user_id                                      ...                                    
1                 1           0           0  ...           0           0           0
2                 1           0           0  ...           0           0           0
3                 1           0           1  ...           0           1           0
4                 1           0           0  ...           0           0           0
5                 1           1           0  ...           0           0           0

[5 rows x 18 columns]

Process finished with exit code 0
# 0代表当月消费过次月没有消费过,1代表当月消费过次月依然消费

def purchase_return(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 pd.Series(status, index = pivoted_purchase.columns)

pivoted_purchase_return = pivoted_purchase.apply(purchase_return,axis = 1)

print(pivoted_purchase_return.head())
         1997-01-01  1997-02-01  1997-03-01  ...  1998-04-01  1998-05-01  1998-06-01
user_id                                      ...                                    
1               0.0         NaN         NaN  ...         NaN         NaN         NaN
2               0.0         NaN         NaN  ...         NaN         NaN         NaN
3               0.0         NaN         1.0  ...         NaN         0.0         NaN
4               0.0         NaN         NaN  ...         NaN         NaN         NaN
5               1.0         0.0         NaN  ...         NaN         NaN         NaN

[5 rows x 18 columns]

Process finished with exit code 0
# 回购率,计算方法和复购率类似,同样的逻辑
(pivoted_purchase_return.sum()/pivoted_purchase_return.count()).plot(figsize=(10,4))
plt.show()

数据分析项目-用户消费行为分析_第16张图片

 分析:

1. 从上图看出,用户的回购率高于复购率,约在30%左右,和老客户差异不大。

2. 从回购率和复购率综合分析,新客的整体质量低于老客,老客的忠诚度(回购率)很好,消费频次稍次

你可能感兴趣的:(python,开发语言,后端)