CDNow网站消费数据分析(Python)

2020-04-06  本文已影响0人  对三zzzzzzz

本文结构:

CD网站用户购买数据分析思路.png

一、项目背景:

1.1、背景介绍:

CDNow曾经是一家在线音乐零售平台,后被德国波泰尔斯曼娱乐集团公司出资收购,其资产总价值在最辉煌时曾超过10亿美元。
本文主要通过分析CDNow网站的用户购买明细来分析该网站的用户消费行为,使运营部门在营销时更加具有针对性,从而节省成本,提升效率。

1.2、数据源介绍

本次分析数据来源CDNow网站的用户在1997年1月1日至1998年6月30日期间内购买CD交易明细。

数据源:
地址:https://pan.baidu.com/s/11sPLzNRUpGghkaIfs1ARfQ
提取码:re0d

字段:
数据集一共有用户ID,购买日期,订单数,订单金额四个字段。

二、提出问题

参照数据分析思路中的数据分析部分。

三、数据处理

3.1、导入数据

3.1.1、导入要用到的模块

import pandas as pd 
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
from datetime import datetime # 用来将字符串转换成时间类型
plt.style.use('ggplot') # 更改设计风格,使用自带形式进行美化
%matplotlib inline  # %内置的命令,jupyter专有的定义,比如在pycharm不常用到,inline意思是做图之后可以在html页面的单元格进行显示

3.1.2、导入数据源

# 1.查看数据发现数据中未包含列标题,所以需要导入数据的时候添加列名
columns = ["用户id","购买日期","订单数量","订单金额"] 
# 2.源数据为txt形式的,所以用pd.read_table;字符串是空格分割,所以用\s+表示匹配任意空白字符(csv数据分分隔是以逗号形式)
data = pd.read_table(r"路径",names=columns,sep='\s+')

3.1.3、查看数据基本信息

# 查看数据字段和记录,默认显示前5行数据
data.head(10) 
image.png
# 查看数据集详细信息(data.shape 以元组形式返回数据集的行数和列数)
data.info() 
image.png

3.2、描述性统计

# 按列对数据进行描述性统计,对用户数据特征进行整体性判断
data.describe()
image.png

3.3、数据处理

3.3.1、缺失值/空值处理

# 查看数据详细信息
data.info()
image.png

3.3.2、数据类型转换

# 将购买日期由数值型转换成日期型
data['购买日期'] = pd.to_datetime(data['购买日期'],format = '%Y%m%d')
data.info() # 验证下数据类型,修改成功
image.png

3.3.3、新增列

# 新增列‘月份’,用于后续月维度的消费行为分析,具体提取哪个时间粒度的视情况而定
data["月份"] = data["购买日期"].values.astype('datetime64[M]')
data.head() # 验证操作结果
image.png

到这里对数据集的整理就已经可以满足分析的需求了,接下来进行具体的分析过程:

四、数据分析

4.1、用户总体消费在时间维度的趋势分析

我们的分析思路是由整体到局部,所以就先从整体看看数据的特征/规律:

# 建立画布,设置画布规格,添加子图
plt.figure(figsize=(16,15)) # 参数21表示画布长度,15表示画布宽度

# 4.1.1 每月总销售额趋势图
plt.subplot(321) # 3x2的画布,在第1块子画布画图
data.groupby("月份").订单金额.sum().plot(fontsize=25) #sontsize设置字号
plt.title("销售额趋势图",fontsize=25) 

# 4.1.2 每月总销量趋势图
plt.subplot(322) # 3x2的画布,在第2块子画布画图
data.groupby("月份")["订单数量"].sum().plot(fontsize=25)  # 用"."和用"[]"均可
plt.title("销量趋势图",fontsize=25)

# 4.1.3 每月消费次数趋势图
plt.subplot(323) # 3x2的画布,在第3块子画布画图
data.groupby("月份").订单数量.count().plot(fontsize=25)
plt.title("消费次数趋势图",fontsize=25)

# 4.1.4 每月消费人数趋势图
plt.subplot(324)# 3x2的画布,在第4块子画布画图
data.groupby("月份").用户id.nunique().plot(fontsize=25) # unique返回值是数组,nunique返回值是数值
plt.title("消费人数趋势图",fontsize=25)

# 4.1.5 每月用户平均消费金额
plt.subplot(325)# 3x2的画布,在第5块子画布画图
(data.groupby("月份").订单金额.sum() / data.groupby("月份").用户id.nunique()).plot(fontsize=25)
plt.title("每月用户平均消费金额",fontsize=25)

# 4.1.6 每月用户平均消费次数
plt.subplot(326) # 3x2的画布,在第6块子画布画图
(data.groupby("月份").订单数量.count() / data.groupby("月份").用户id.nunique()).plot(fontsize=25)
plt.title("每月用户平均消费次数",fontsize=25)

plt.tight_layout(pad=2) # 用于设置子图见的间距
plt.show() # 查看图表
image.png

前四个折线图:消费金额、销量、消费次数、用户数;
整体趋势基本一致,都是1997年前三个月数据异常高,随后骤降,然后趋于平稳;
为什么会出现这种异常现象呢?初步猜测要么是前三个月有异常值,要么就是受营销活动或者其他外部因素的影响,但这里没有更多的数据提供验证素材,所以也无法判断其原因。

后两个折线图:平均消费金额、平均消费次数;
用户平消费金额大概为50,前三个月低,后续在[47,5]波动;用户平均消费次数,也是前三个月低,后续上升,并维持在1.35次左右,说明cd消费这个复购率着实有点让人着急;

两个数据趋势基本一致,相较于销售额等数据,前面三个月数据反而低,后续才慢慢上升,结合两种趋势图来看,在消费次数和金额稳定的情况下,用户复购下降或者用户数下降会导致总体销售额和销量的下降,关于这个问题的验证,稍后在复购率和留存率的分析中再探究。

4.2、用户个体消费数据分析

总体看完,大概明白了整体趋势是一个怎样的状况,那么接下来就深入细节,从个体角度看看又呈现什么样的特点呢?

4.2.1、消费金额和消费次数的描述性统计分析

# 根据用户id分组,统计单个用户的订单数和订单额
group_userid = data.groupby("用户id").sum()
group_userid.head() # 查看数据
image.png
# 计算描述统计数据
group_userid.describe()
image.png

4.2.2、消费金额和消费次数关系(散点图)

# 查看消费数量随消费金额的变化关系
group_userid.plot.scatter(x="订单数量",y="订单金额",fontsize=13)
plt.title("消费金额和消费次数关系",fontsize= 18)

# 如果希望对销售金额设置限制条件,排除异常值,可以使用query()函数:
# group_userid.query('订单金额 < 4000').plot.scatter(x='订单金额',y='订单数')
image.png

4.2.3、消费金额分布(直方图)

group_userid["订单金额"].plot.hist(bins=30,fontsize=15) # bins=30,就是分成30组
# group_userid["订单金额"]和group_userid.订单金额返回值均为float64类型
# 纵坐标代表的是用户id,也就是人数。因为group_userid.订单金额实际上是个series
plt.xlabel("订单金额",fontsize=15)
plt.ylabel("订单人数",fontsize=15)
plt.title("消费金额分布图",fontsize=18)
image.png
# 只看订单金额小于1000的用户的消费金额
group_userid.query("订单金额 < 1000").订单金额.plot.hist(bins=40,fontsize=15)
plt.xlabel("订单金额",fontsize=15)
plt.ylabel("订单人数",fontsize=15)
plt.title("消费金额分布图",fontsize=18)
image.png

4.2.4、消费次数分布(直方图)

# 有了前面的经验,结合描述性分析的结果,这里我们先对数据进行筛选后再制作可视化查看
group_userid.query("订单数量 < 80").订单数量.plot.hist(bins=20,fontsize=15)
plt.xlabel("订单数量",fontsize=15)
plt.ylabel("订单人数",fontsize=15)
plt.title("消费次数分布图",fontsize=18)
image.png

4.3、用户消费周期分析

4.3.1、用户购买周期(按订单日期)

4.3.1.1、用户消费周期描述性统计分析

# 先把每个用户每次购买的时间间隔计算出来,这里用到的方法是shift()
# 定义一个函数,用于计算购买时间间隔
def diff(data):  
    d = data.购买日期 - data.购买日期.shift(1)
    return d
# 计算购买时间间隔
purchase_period = data.groupby("用户id").apply(diff) # 需要注意的是 这里的返回值是一各timedelta,不能直接做直方图的
purchase_period.head(10) 
# 这里使用函数实现的意义是练习函数编写能力,不用编写函数实现也很简单
image.png

上面就是每个用户每一次购买的时间间隔,下面计算用户购买间隔的描述性统计数据

purchase_period.describe() #用户消费周期描述性统计分析
image.png
# 定义一组series,用于测试
x = pd.Series([1,2,3,4,5])
x
image.png
x.shift() # 默认参数是1,也就是向下偏移一个单元/位置
image.png
x.shift(-1) # 向上偏移1个位置
image.png

4.3、用户消费周期分布

plt.figure(figsize=(15,6)) # 建立一张画布
plt.hist(purchase_period / np.timedelta64(1,"D"),bins= 30) # 将timedelta类型转换成数值类型
plt.xlabel("购买周期",fontsize=18)
plt.ylabel("人数",fontsize=18)
plt.title("用户消费周期愤分布",fontsize=25)
image.png

4.3.2、用户生命周期(按用户首次和最后一次消费时间)

接下来计算每一位用户生命周期,这里定义用户第一次消费至最后一次消费为整个用户生命周期全过程。

# 用户首次购买时间
orderdate_min = data.groupby("用户id").购买日期.min()
orderdate_min.head()
image.png
# 用户最后一次购买时间
orderdate_max= data.groupby("用户id").购买日期.max()
orderdate_max.head()
image.png

4.3.2.1用户生命周期描述性统计分析

# 用户生命周期计算:最后一次减第一次
life_cycle = (orderdate_max - orderdate_min)
life_cycle.head()
image.png
# 做描述性行统计
life_cycle.describe()
image.png

4.3.2.2、用户生命周期分布

# life_cycle数据类型是timedelta,所以得先转换成数值
(life_cycle / np.timedelta64(1,"D")).hist(bins=30)
image.png

先将 life_cycle数据结构由series转换成Dataframe,此处用到的方法是重置索引,方便后面筛选过滤

life_cycle = (orderdate_max - orderdate_min).reset_index()
life_cycle.head()  # 时间间隔仍为timedelta格式,后续做直方图还得转换成数值类型
image.png
# 过滤掉仅消费一次的用户后,用户生命周期的分布
life_cycle["购买日期"] = life_cycle.购买日期 / np.timedelta64(1,"D") # 转换成数值类型
life_cycle.head()
image.png
plt.figure(figsize=(15,6))
life_cycle[life_cycle["购买日期"] > 0].购买日期.hist(bins=100) # hist没有fontsize属性
image.png

筛选掉仅消费一次后的用户之后是上述情况,再来看看此时的用户生命周期的描述性统计数据有什么变化:

life_cycle[life_cycle["购买日期"] > 0].购买日期.describe()
image.png

4.4、用户质量分析

4.4.1、仅消费一次用户占总用户的比例

# 按用户id分组计算其购买日期的最大值和最小值
group_userid_date_min_max = data.groupby("用户id")["购买日期"].agg(["min","max"]).reset_index()
group_userid_date_min_max.head() # 返回值是一个dataframe,这点很关键
image.png
# 统计用户首次下单时间和最后一次下单时间相等的人数,然后做饼图观察比例
new_user = (group_userid_date_min_max["min"] == group_userid_date_min_max["max"] ).value_counts()
new_user
image.png
# 用饼图观察百分比
plt.figure(figsize=(8,5))
plt.pie(new_user,
        autopct="%.1f%%",
        shadow= True,
        explode=[0.07,0], 
       textprops={"fontsize":15},)
# 设置x,y轴刻度一致,这样饼图才能是圆的
plt.axis("equal")
plt.legend(["仅消费一次人数","费多次人数"])

#autopct,圆里面的文本格式,%.1f%%表示小数有三位,整数有一位的浮点数
#shadow,饼是否有阴影
#explode,将某部分爆炸出来, 使用括号,将第一块分割出来,数值的大小是分割出来的与其他两块的间隙
#startangle,起始角度,0,表示从0开始逆时针转,为第一块。一般选择从90度开始比较好看
#pctdistance,百分比的text离圆心的距离
#patches, l_texts, p_texts,为了得到饼图的返回值,p_texts饼图内部文本的,l_texts饼图外label的文本
image.png

4.4.2、复购率分析

复购率:
在某时间窗口内,消费两次及以上的用户在总消费用户中占比。
这里的时间窗口是月,如果一个用户在同一天下了两笔订单,这里也将他算作复购用户

#每个用户在每月的订单数
pivoted_data=data.pivot_table(index='用户id',columns='月份',values='购买日期',#pivot_table透视表
                       aggfunc='count').fillna(0) #某些用户在某月没有消费过,用nan表示,这里用0填充

pivoted_data.head()
image.png

案例中,我希望统计每个用户在每月的订单量,所以用户id是index,月份是column。values是将哪个值进行计算,aggfunc是用哪种方法。于是这里用values=购买日期和aggfunc=count,统计里order_dt出现的次数,即多少笔订单。
使用数据透视表,需要明确获得什么结果。有些用户在某月没有进行过消费,会用NaN表示,这里用fillna填充。

#转换:消费2次以上记为1,消费1次记为0,消费0次记为NAN  
#applymap针对dataframe所有数据
pivoted_data_trans=pivoted_data.applymap(lambda x: 1 if x>1 else np.nan if x==0 else 0)
pivoted_data_trans.head()
image.png

applymap针对DataFrame里的所有数据。用lambda进行判断,因为这里涉及了多个结果,所以要两个if else,记住,lambda没有elif的用法。

#count统计所有非空数据个数表示总消费用户数,sum计算非0数据的和表示消费两次以上的用户数
repurchase_rate = pd.DataFrame(pivoted_data_trans.sum()/pivoted_data_trans.count()).reset_index()
repurchase_rate.columns = ["日期", "复购率"]
repurchase_rate["日期"] = repurchase_rate.日期.astype(str).apply(lambda x:x[0:8])

plt.figure(figsize = (15,6))
plt.plot(repurchase_rate.日期, repurchase_rate.复购率)
plt.xlabel("日期", fontsize=18)
plt.ylabel('复购率',fontsize=18)
plt.title('复购率的变化',fontsize=25)
image.png

4.4.3、回购率分析

回购率:
某一个时间窗口内消费的用户,在下一个时间窗口仍旧消费的占比。
比如,1月消费用户是1000,他们中有300个用户2月依然消费,那么回购率就是30%。
这里的维度是月,所以一个月内消费多次计为一次。

# 建立用户每月消费的数据透视表
group_month_user_order = data.pivot_table(index= "用户id",
                                         columns= "月份",
                                         values="订单金额", 
                                         aggfunc= "mean").fillna(0)
columns_month=data.月份.sort_values().astype('str').unique() # 定义的列名后续还会用到
group_month_user_order.columns = columns_month
group_month_user_order.head()
image.png

因为这里只需要用户当月有消费记录即可,所以只是随便找一个字段用于计数,这里会用的是订单金额的平均值,使用订单数量或者sum也是完全可以的

# 格式化数据,将有消费的记录为1,后续用sum求和,没有消费的记为0,后续用count计数
# 用applymap+lambda转换数据,只要有过购买,记为1,反之为0。
pivoted_repurchase = group_month_user_order.applymap(lambda x : 1 if x > 0 else 0)
pivoted_repurchase.head()
image.png
# 定义一个函数,用于判断用户当月是否属于回流用户
def repurchase(table):
    status = []
    for i in range(18):
        # 先判断第一个月的消费情况
        if i == 0:
            if table[0] == 1:  #第一个月有消费
                status.append(0)
            else:             # 第一个月没有消费
                status.append(np.nan)
        # 判断后续17个月的消费情况
        else:
            if table[i] == 1: # 当月有消费
                if table[i - 1] == 1: # 上月有消费
                    status.append(1) # 回流用户
                else:               #上月无消费
                    status.append(0)
            else:               # 当月无消费
                if table[i - 1] == 1:   #上月有消费
                    status.append(0)
                else:                   #上月无消费
                    status.append(np.nan)
    return pd.Series(status,index=columns_month)  # 返回一个dataframe,使用pd.Series方法
pivoted_repurchase_return = pivoted_repurchase.apply(repurchase,axis=1)
pivoted_repurchase_return.head()
image.png
# 计算每月回购率,并将结果通过重置索引,添加列名保存为Datafram格式。 重置索引转换成dataframe
return_purchase_rate = (pivoted_repurchase_return.sum() / pivoted_repurchase_return.count()).reset_index()
return_purchase_rate.head() 
image.png
# 添加列名
return_purchase_rate.columns = ["日期","回购率"] 
# 修改日期列名为 年+月 格式
return_purchase_rate["日期"] = return_purchase_rate.日期.astype(str).apply(lambda x:x[:-3])
return_purchase_rate.head()
image.png
# 可视化展示观察特征
plt.figure(figsize=(15,6))
plt.plot(return_purchase_rate.日期,return_purchase_rate.回购率)
plt.xlabel("日期",fontsize= 25)
plt.ylabel("回购率",fontsize= 25)
plt.title("回购率变化情况",fontsize=25)
image.png

4.4.4、留存率分析

留存率是指用户在第一次消费后,有多少比率进行第二次消费。
建立计算留存率的基表,基表结构为统计不同用户每一次消费举例第一次消费的时间间隔 具体方法是通过merge连接用户数据和用户消费时间最小值,然后计算时间差,具体如下:

# 用户第一次消费的统计表,用于后续merge的子表,计算用户每一次的消费时间间隔
user_orderdate_min = data.groupby("用户id").购买日期.min().reset_index()
user_orderdate_min.head()
image.png
# 选取data子集,用于建立基表的子表
data2 = data[["用户id","购买日期","订单数量","订单金额"]]
data2.head()
image.png
# 然后将data2和user_orderdate_min进行merge,用于计算消费时间间隔,也是此部分计算的基表
user_retention = pd.merge(data2,user_orderdate_min,how="inner",on="用户id",suffixes=("","_min"))
user_retention.head()
image.png
# 新增一列 消费间隔,用户储存用户每次消费距离第一次消费的时间间隔
user_retention["消费间隔"] = user_retention.购买日期 - user_retention["购买日期_min"]
user_retention.head()
# 上面的返回值是timedelta类型的,将其转换成数值类型的
user_retention["消费间隔"] = user_retention.消费间隔 / np.timedelta64(1,"D")
user_retention.head()
image.png
# 将消费间隔分组
bin=[0,3,7,15,30,60,90,180,365]
# 新增一列 消费间隔_bin 用于储存分组后的数据
user_retention["消费间隔_bin"] = pd.cut(user_retention.消费间隔,bins=bin)
user_retention.head()
image.png
# 建立数据透视表,用于统计不同时间窗口的用户消费金额
#用户第一次消费之后,后续各时间段的消费总额
pivoted_user_retention = user_retention.pivot_table(index='用户id',
                                                    columns='消费间隔_bin',
                                                    values='订单金额',
                                                    aggfunc=sum, # 有无引号均可
                                                    
                                                    # Pandas函数pivot_table会默认删除含有空值的行,用dropna=False保持NaN的值。
                                                    dropna=False) 
pivoted_user_retention.head()
image.png

这样就把所有用户的所有消费时间间隔划分到了每一个组当中,下面先看下其描述性数据统计,然后进行格式化,制作直方图观察留存率的分布情况

# 用户留存描述统计,这里主要看下平均值
pivoted_user_retention.mean()
image.png
# 格式化 pivoted_user_retention 表,用于统计人数
pivoted_user_retention_tmp = pivoted_user_retention.applymap(lambda x: 1 if x > 0 else 0)
pivoted_user_retention_tmp.head()
image.png
# 计算各组所占百分比,这里同样用的是sum和count,与之前一样。
((pivoted_user_retention_tmp.sum()/ pivoted_user_retention_tmp.count())).plot.bar(figsize=(10,6))
plt.xlabel('留存周期',fontsize=18)
plt.title('留存率占比',fontsize=25)
image.png

4.4.5、客户贡献率分析

按照用户id分组,对用户的消费金额/销量进行累计求和 ,然后与总销售额比,得到比率,横坐标是用户的id

4.4.5.1、用户销售额贡献分析

计算百分之多少的用户占了百分之多少的销售额

# 先将用户订单金额按升序排列,逐行累计订单金额,最后一行是订单总金额
user_amount = data.groupby("用户id").订单金额.sum().sort_values().reset_index()
user_amount.head()
image.png
# 新增一列 计算订单金额的累加和
user_amount["累计订单额"] = user_amount.订单金额.cumsum()
user_amount.tail()
image.png
# 订单金额总计
amount_total = user_amount.累计订单额.max()
amount_total
image.png
# 转化成百分比
user_amount["占比"] = user_amount.累计订单额 / amount_total
user_amount.tail()
image.png
# 做折线图,观察规律
user_amount.占比.plot(figsize= (9,5))
plt.xlabel("用户id",fontsize=18)
plt.ylabel("占比",fontsize=18)
plt.title("用户销售额贡献率", fontsize=25)
image.png

下面继续看销量方面的贡献率

4.4.5.2、用户销量贡献分析

计算百分之多少的用户占了百分之多少的销量:

# 先将用户订单数量按升序排列,逐行累计订单数量,最后一行是订单总量
user_amount = data.groupby("用户id").订单数量.sum().sort_values().reset_index()
# 新增一列 计算订单数的累加和
user_amount["累计订单量"] = user_amount.订单数量.cumsum()
# 订单金额总计
amount_total = user_amount.累计订单量.max()
# 转化成百分比
user_amount["占比"] = user_amount.累计订单量 / amount_total
# 做折线图,观察规律
user_amount.占比.plot(figsize= (10,6))
plt.xlabel("用户id",fontsize=18)
plt.ylabel("占比",fontsize=18)
plt.title('用户累计销量贡献比', fontsize=25)
image.png

4.5、用户分层

4.5.1、按用户价值分层(RFM模型)

为了进行精细化运营,可以利用RMF模型对用户价值指数(衡量历史到当前用户贡献的收益)进行计算,其中:
最近一次消费-R:客户最近一次交易时间的间隔。R值越大,表示客户交易发生的日期越久,反之则交易发生的日期越近。
消费频率-F:客户在最近一段时间内交易的次数。F值越大,表示客户交易越频繁,反之则表示客户交易不够活跃。
消费金额-M:客户在最近一段时间内交易的金额。M值越大,表示客户价值越高,反之则表示客户价值越低。 根据上述三个维度,对客户做细分。


image.png
image.png
# 建立rfm基表
rfm = data.pivot_table(index = '用户id',
                       values = ['订单金额','购买日期','订单数量'],
                       aggfunc = {'订单金额':'sum',
                                  '购买日期':'max',
                                  '订单数量':'sum'})
rfm.head()
image.png
# 计算r值:日期的最大值与当前日期的差值为R
rfm['R'] = (rfm['购买日期'].max() - rfm['购买日期']) / np.timedelta64(1,'D')
rfm.head()
image.png
# 对列名进行重命名:
rfm.rename(columns = {'订单金额':'M',
                      '订单数量':'F'},
                       inplace=True)
rfm.head()
image.png
# 客户层次的定义
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)
image.png
# 按照标签分组计算不同标签的销售额和销量
rfm.groupby("label").sum()
image.png
# 再看看不同标签用户的人数
rfm.groupby('label').count()
image.png
# 增加字段color,为下面作图做准备
rfm.loc[rfm.label == '重要价值客户','color'] = 'g'
rfm.loc[~(rfm.label == '重要价值客户'),'color'] = 'r'
rfm.plot.scatter("F",'R',c = rfm.color)
image.png

4.5.2、按用户活跃程度分层(按活跃度)

新用户的定义是第一次消费;
活跃用户即老客,在某一个时间窗口内有过消费。
不活跃用户则是时间窗口内没有消费过的老客。
回流用户是在上一个窗口中没有消费,而在当前时间窗口内有过消费。
以上的时间窗口都是按月统计,
比如某用户在1月第一次消费,那么他在1月的分层就是新用户;他在2月消费国,则是活跃用户;3月没有消费,此时是不活跃用户;4月再次消费,此时是回流用户,5月还是消费,是活跃用户。

下面是具体实现过程:

#将用户消费数据进行数据透视:
data3 = data.pivot_table(index = "用户id",
                         columns = "月份",
                         values = '购买日期',
                         aggfunc = 'count').fillna(0)
data3.head() 
image.png

图中的数字0/1/2代表当月的消费次数

# 格式化透视表里的数据,方便后续函数判断用户状态
data3 = data3.applymap(lambda x:1 if x>0 else 0)
data3.tail()
image.png

0代表当月没有消费,1代表有消费

# 创建列表,储存列名
col = ['1997-01-01', '1997-02-01', '1997-03-01', '1997-04-01',
               '1997-05-01', '1997-06-01', '1997-07-01', '1997-08-01',
               '1997-09-01', '1997-10-01', '1997-11-01', '1997-12-01',
               '1998-01-01', '1998-02-01', '1998-03-01', '1998-04-01',
               '1998-05-01', '1998-06-01']
def active_status(data):
    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 pd.Series(status,index = col)
# 可得到一张不同用户在不同月份的不同状态主要为了统计起来更加方便而加进去。
data4 = data3.apply(lambda x : active_status(x),axis=1)
data4.head()
image.png
#把unreg替换成NaN,它是「未来」才作为新客.再用fillna(0)把空值填为0。然后转置,把月份作为索引行,状态作为列,得到如下的表
data5 = data4.replace('unreg',np.NaN).apply(lambda x:pd.value_counts(x)).fillna(0).T
data5
image.png

从表中可以看出,新客都是集中在前三个月,回流用户整体在1000左右,而不活跃用户数量随时间稍有上升。

#作出非堆积效果图:
data6 = data5.reset_index()
labels = data6[['active','new','return','unactive']].columns
plt.figure(figsize=(15,6))
data5.plot.area(figsize=(12,5))
plt.xlabel('月份')
plt.ylabel('消费人数')
plt.title('每月的消费人数')
plt.legend()
image.png

生成面积图,比较丑。因为它只是某时间段消费过的用户的后续行为,蓝色和灰色区域都可以不看。只看紫色回流和红色活跃这两个分层,用户数比较稳定。这两个分层相加,就是消费用户占比(后期没新客)。

#每一层用户占总用户的比例
data7 = data5.apply(lambda x : x / x.sum(),axis=1)
data7.head()
image.png

回流用户占总用户的比例

data7.plot(figsize=(12,6))
plt.xlabel('月份',fontsize=18)
plt.ylabel('占比',fontsize=18)
plt.title('不同活跃度用户扎占比',fontsize=25)
plt.legend()
image.png

结论/建议 :

image.png

1、整体趋势

2、用户个体特征

3、用户的消费周期

4、用户质量

上一篇 下一篇

猜你喜欢

热点阅读