python数据分析:用户消费情况数据分析
本次分析数据介绍:
数据为某奶茶店2018年1月-2019年6月的销售数据,共计69,659项数据,用户共计23,570名;
数据集共4个字段:
user_id: 用户id
order_id: 购买日期
order_prodect: 购买产品数
order_account: 购买金额
明确问题(本次数据分析目的)
用户消费趋势分析(按月)
用户个体消费分析
用户消费行为分析
用户复购率和回购率分析
分析思路
理解数据
我们导入数据后简单看一下:
# 导入数据
df = pd.read_excel('MilkyTea_master.xlsx')
检查一下各字段类型:
数据清洗
本次抽样为全抽,不再进行选择子集;不再涉及列重命名;
1.数据类型转换
根据以上分析,我们需把用户id转化为字符串,把时间order_id转化为时间格式:
① 时间类型转换
# 时间类型转换,增加‘month’列
df['order_dt'] = pd.to_datetime(df.order_dt,format='%Y%m%d')
df['month'] = df.order_dt.values.astype('datetime64[M]')
② 字符串类型转换
df['user_id'] = df['user_id'].apply(lambda x : str(x))
2.数据排序
# 按照“order_dt”排序
df = df.sort_values(by = 'order_dt',ascending =True)
3.缺失值处理
我们检查是否存在缺失值:
for i in df.columns:print(df[i].isnull().value_counts())
无需进行缺失值处理;
4.异常值处理
检查描述统计信息,查看是否存在异常
以上,我们可以发现:
大部分订单只购买了少量商品(平均值2.41),有一定极值干扰;
影虎的消费金额比较稳定(平均值35.89元,中位数25.98元),有一定极值干扰;
最后,我们对index重新命名:
df = df.reset_index(drop = True)
构建模型
接下来,我们对问题进行分析:
1.用户消费趋势分析(按月)
我们按月度对用户进行分析,须将数据框按月分组:
g_month = df.groupby('month')
1 每月消费金额
# 每月消费总金额
g_month.order_account.sum()
2 每月消费次数
# 每月消费总次数
g_month.user_id.count()
3 每月购买数量
# 每月购买数量
g_month.order_products.sum()
4 每月消费人数
# 每月消费人数
g_month.user_id.apply(lambda x : len(x.drop_duplicates()))
以上我们也可用以下方式来统一分析:
df_table = df.pivot_table(index = 'month',values = ['order_products','order_account','user_id'],aggfunc = {'order_products':'sum','order_account':'sum','user_id':'count'})
我们将分析结果进行数据可视化:
sns.set_palette('summer')
sns.set_style('darkgrid')
f = plt.figure(figsize = (20,16))
f.add_subplot(3,1,1)
g_month.order_account.sum().plot()
plt.title('order_account')
f.add_subplot(3,1,2)
g_month.order_products.sum().plot()
plt.title('order_products')
f.add_subplot(3,1,3)
g_month.user_id.count().plot()
plt.title('user_id')
2.用户个体消费
与按月分析不同,此次需要对数据库按用户id进行分组:
1.用户消费金额、消费次数的描述统计
# 按照用户进行分组
g_user = df.groupby('user_id')
# 用户消费金额、消费次数的描述统计
g_user.sum().describe()
用户平均购买奶茶7杯,中位数为3杯,说明小部分的用户购买了大量的奶茶;
用户平均消费106元,中位数43元,说明小部分用户购买大量的奶茶,存在极值干扰;
2.用户消费金额和消费次数的散点图
# 用户消费金额和消费次数的散点图
g_user.sum().plot.scatter(x = 'order_account', y = 'order_products')
不是那么明显,我们选择购买金额<6000的数据集进行分析(去除极值):
# 用户消费金额和消费次数的散点图
g_user.sum().query('order_account < 6000').plot.scatter(x = 'order_account', y = 'order_products')
3.用户消费金额分布图
# 用户消费金额分布图
g_user.sum().order_account.plot.hist(bins = 20)
可知,用户消费金额大部分呈集中趋势,小部分异常值干扰了判断;
我们可以运用切比雪夫定理:‘所有数据中,至少有24/25(或96%)的数据位于平均数5个标准差范围内’,故,我们用7+16.98*5 ≈100 来排出异常值:
g_user.sum().query('order_account < 100').order_account.plot.hist(bins = 20)
4**用户累计消费占比(**百分之多少的用户占百分之多少的销售额)
# 用户累计消费占比(百分之多少的用户占百分之多少的销售额)
g_user.sum().sort_values('order_account').apply(lambda x : x.cumsum()/ x.sum()).reset_index().order_account.plot()
3.用户消费行为分析
同样,我们依旧按用户分组进行分析:
1)用户第一次消费(首购)
# 用户第一次消费(首购)
g_user.min().order_dt.value_counts().plot()
用户首购分布:集中在前3月;在2月中旬期间,波动较剧烈;
2.用户最后一次消费
# 用户最后一次消费
g_user.max().order_dt.value_counts().plot()
用户最后一次购买时间分布较广,大部分最后一次购买集中在前3个月,说明可能存在很多用户购买了一次没有再复购;随着时间递增,最后一次购买的用户数量也在上升,消费呈流失上升状态;
3.新老客户消费比
① 多少用户仅消费1次
# 多少用户仅消费1次
user_life = g_user.order_dt.agg(['min','max'])
(user_life['min'] == user_life['max']).value_counts()
# 可视化(饼图)
plt.pie((user_life['min'] == user_life['max']).value_counts(normalize = True),autopct='%.2f%%',labels = (user_life['min'] == user_life['max']).value_counts().index)
我们发现,超过一半用户仅消费一次;
② 每月新客占比
# 每月新客占比
g_user.min().month.value_counts() / g_month.user_id.apply(lambda x : len(x.drop_duplicates()))
我们发现,首月消费新客占比100%,第二、三月逐渐新客数量占比减少,第四月后无新客;
4.用户分层
① RFM用户分层
这里需要补充一下RFM分析:
RFM是3个指标的缩写,最近一次消费时间间隔(Recency),消费频率(Frequency),消费金额(Monetary)。通过这3个指标对用户分类。
最近一次消费时间间隔(R),上一次消费离得越近,也就是R的值越小,用户价值越高;
消费频率(F),购买频率越高,也就是F的值越大,用户价值越高;
消费金额(M),消费金额越高,也就是M的值越大,用户价值越高;
# RFM用户分层
rfm = df.pivot_table(index = 'user_id',values = ['order_products','order_account','order_dt'],aggfunc= {'order_products':'sum','order_account':'sum','order_dt':'max'})
我们对最后一次消费时间计时间间隔,并对透视结果列重命名:
rfm['R'] = (rfm.order_dt.max() - rfm.order_dt) / np.timedelta64(1,'D')
rfm.rename(columns={'order_products':'F','order_account':'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.Md = {'111':'重要价值客户','011':'重要保持客户','101':'重要发展客户','001':'重要挽留客户','110':'一般价值客户','010':'一般保持客户','100':'一般发展客户','000':'一般挽留客户'}result = d[label]return result
rfm['label'] = rfm[['R','F','M']].apply(lambda x : x - x.mean()).apply(rfm_func,axis=1)
接着,我们对‘label’列分组求和:
rfm.groupby('label').sum()
也可以分组后计数:
rfm.groupby('label').count()
从RFM分层可知,大部分的用户是一般挽留客户,重要价值客户和重要保持客户合计约占20%;
我们进行可视化:
rfm.loc[rfm.label == '重要价值客户','color'] = 'g'
rfm.loc[rfm.label != '重要价值客户','color'] = 'r'
rfm.plot.scatter('F','R',c = rfm.color)
② 用户生命周期-新、老、活跃、回流、流失
# 用户生命周期-新、老、活跃、回流、流失
pivoted_counts = df.pivot_table(index = 'user_id',columns= 'month',values= 'order_dt',aggfunc= 'count').fillna(0)
需要对结果进行简化,如果购买次数大于0(大于等于1),有购买为1,无购买为0:
# 进行简化
df_purchase = pivoted_counts.applymap(lambda x : 1 if x>0 else 0)
根据本月是否消费、前期是否消费、上月是否消费等多层维度,将用户划分为未注册、新注册、活跃、不活跃、回流、流失;
def active_statu(data):status = []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 statuspurshase_stats = df_purchase.apply(active_statu,axis=1)
purshase_stats = pd.DataFrame(purshase_stats)[0].apply(pd.Series)
purshase_stats.columns = pivoted_counts.columns
把‘unreg’用NAN替换,并对每月的用户状态进行统计:
purshase_stats_ct = purshase_stats.replace('unreg',np.NAN).apply(lambda x : pd.value_counts(x))
# 转置
purshase_stats_ct.fillna(0).T
可视化:
purshase_stats_ct.fillna(0).T.plot.area()
可以逐行计算百分比:
# 可以逐行计算百分比
purshase_stats_ct.fillna(0).T.apply(lambda x : x/x.sum(),axis = 1)
purshase_stats_ct.fillna(0).T.apply(lambda x : x/x.sum(),axis = 1).plot.area()
5)用户购买周期(按订单)
① 用户订单周期
# 用户订单周期
order_diff = g_user.apply(lambda x: x.order_dt - x.order_dt.shift())
查看描述统计:
② 用户订单分布
(order_diff/np.timedelta64(1,'D')).hist(bins=20)
订单周期呈指数分布
用户平均购买周期是68天
绝大部分用户购买周期都超过100天
6.用户生命周期(按第一次&最后一次消费)
我们查看用生命周期(第一次&最后一次)描述统计:
(user_life['max'] - user_life['min']).describe()
用户生命周期受只购买一次的用户影响较大
用户平均消费时间差134天,中位数仅0天
4.用户复购率和留存率
1)复购率
自然月内,购买多次的用户占比:
我们根据上述的对用户按月统计购买量pivoted_counts来分析:
如果当月购买了1次以上(大于1),则为1,存在复购;若购买了1次,为0;当月购买了0次,则为NAN;
purchase_r = pivoted_counts.applymap(lambda x : 1 if x > 1 else np.NAN if x == 0 else 0 )
求和,为当月复购的人数;计数,为当月购买人数:
(purchase_r.sum() / purchase_r.count()).plot(figsize = (10,4))
复购率稳定在20%左右,前三月因为有大量的新用户涌入,而这批用户只购买了一次,所以导致复购率低;
2.回购率(留存率)
曾经购买过的用户某一时间内再次购买的占比:
定义函数,如果当月购买,下月也购买为1;如果当月购买下月未购买,为0;如果当月未购买,则为NAN;
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 statuspurchase_b = df_purchase.apply(purchase_back,axis=1)
purchase_b = pd.DataFrame(purchase_b)[0].apply(pd.Series)
purchase_b.columns = pivoted_counts.columns
回购率 = 次月再次购买/本月购买人数
(purchase_b.sum()/purchase_b.count()).plot(figsize = (10,4))
分析结论
用户增长阶段仅在前三月,后期消费均为老客户;消费用户群体较为固定;
超过50%的用户仅在前三月消费了一次,后期长期处于不活跃状态;用户消费呈流失上升状态;
60%的销售金额是被前5000名(近20%)的人贡献。
用户增长阶段仅在前三月,后期消费均为老客户;消费用户群体较为固定;
超过50%的用户仅在前三月消费了一次,后期长期处于不活跃状态;用户消费呈流失上升状态;
60%的销售金额是被前5000名(近20%)的人贡献。
python数据分析:用户消费情况数据分析相关推荐
- 电商数据分析--用户行为分析
电商数据分析–用户行为分析 数据分析流程: 明确目的 获取数据 数据探索和预处理 分析数据 得出结论 验证结论 结果展现 用户行为是指用户在产品上产生的行为.(登陆.浏览.购买.加入购物车) 用户行为 ...
- 用户消费数据分析,基于python
目录 一.数据的类型处理 1.1 数据加载 1.2 观察数据 二.按月数据分析 2.1 用户每月花费的总金额 2.2 所有用户每月的产品购买量 2.3 所有用户每月的消费总次数 2.4 统计每月的消费 ...
- 使用Python对淘宝用户行为进行数据分析
淘宝用户数据分析 1 分析背景与意义 2 分析思路 3 分析内容 3.1 提出问题 3.2 理解数据 3.3 数据清洗 3.3.1 数据导入 3.3.2 缺失值分析 3.3.3 选取时间范围 3.3. ...
- python商品销售情况数据分析_用python分析小红书销售情况
一.分析目的 本文将通过对小红书销售表3万余条数据的分析,找到影响销售额的因素. 二.理解数据 先看下数据集字段基本信息 import pandas as pd import numpy as np ...
- 项目实战--用户消费数据分析
文章目录 引入包 一.数据预处理 二.按月对数据分析 三.用户个体消费数据分析 四.用户消费行为分析 五.用户的生命周期 引入包 本项目所用数据为[密码:pfj6]:CDNOW_master.txt ...
- 数据分析:旅游景点销售门票和消费情况分析
数据分析:旅游景点销售门票和消费情况分析 作者:AOAIYI 作者简介:Python领域新星作者.多项比赛获奖者:AOAIYI首页
- 数据分析项目:CDNOW用户消费数据分析(基于MySQL实现)
CDNow网站销售数据分析 项目背景 分析目的及思路 数据处理 数据导入 数据清洗 1.字段空格处理 2.数据类型转换 3.缺失数据处理 4.数据重复处理 5.数据0值 数据分析 产品销售分析 产品价 ...
- python画图横轴刻度间隔设置为3个月_Python 天气情况数据分析及可视化
Python 天气情况数据分析及可视化 环境配置 Pycharm开发环境 python 版本 python3.7 Anconda 集成开发环境 第三方库导入 ## pip install 模块 清华大 ...
- 数据分析案例--学生用户消费分析
1.导入相关python包 import pandas as pd import numpy as np import matplotlib.pyplot as plt %matplotlib inl ...
最新文章
- java抛出自定义异常_10 个深恶痛绝的 Java 异常。。
- html实体编码遇上js代码
- 不歧视双非的计算机院校,公平!考研西工大,双非院校倒数第一名考生上岸,本校考生被刷...
- 浅析企业网站应该如何选择适合自己的服务器?
- zxing开源库工作流程源码详解
- 面试题: mysql 数据库已看 sql安全性 索引 引擎 sql优化
- HTML表单的enctype属性详解{转}
- 把16进制值转换成颜色颜色16进制值表 .
- 浅谈游戏单位属性模块设计:属性组成、分级、计算与同步
- 英雄会被表彰,这些技术与代码也将被历史铭记
- 自定义验证之整数(包括0和负数)
- 通信基站能耗综合管理系统
- 【转】区块链底层架构概览:第一原则框架
- 固定螺栓系统行业调研报告 - 市场现状分析与发展前景预测(2021-2027年)
- 千江有水千江月 万里无云万里天
- castle典范英语 storm_fb08 新版典范英语1-9年级 PDF文档+MP3音频 含练习册及教学参考...
- 在UNIX \ Linux终端中的可视化磁盘空间和磁盘使用情况小工具 - Vizex
- 1)java基本语法
- ORA-01507错误
- ElementUI 获取el-table表格选中行信息及清除选中行
热门文章
- 5月书讯 | 华章IT图书上新啦!重磅新书在线投喂...
- 云时代下最强的“管理驾驶舱”制作方法,你学会了吗?
- Spring Boot DTO 验证示例
- 珍爱网有人退费成功吗?珍爱网退费流程攻略详解大全!
- Java -- 面向对象【接口】
- SQL Server 数据库之导入导出数据
- 数据库、数据库管理系统、SQL和图形界面工具的关系
- el-tree中实现拖拽遇到的问题
- java 正负循环_为什么递增Java int最终导致负数?
- java plugin_Java Plugin类代码示例