更多 Python 数据处理的干货,敬请关注!!!!
发现许多小伙伴入门Python几个月,还是低效率做数据处理。这套课程以形象的示意图,精心安排的案例,循序渐进带你玩转数据处理分析神器——pandas,课程中还有分析案例噢,干货满满!
前言
这是一个关于在线音乐零售平台的用户消费分析案例,在网上到处可见,听闻不少培训机构也用于数据分析案例。我大概看了一些其他的文章,基本是千篇一律。
如果我今天也用同一个思路"水"一篇文章就没有多大意思。因此,这次我会分享一些你可能极少看到的一种 pandas 的代码组织方式,我相信你会有所收获。
你可以网上搜索"用户消费分析 pandas" 查阅其他同类文章作为对比学习
数据背景
案例数据为 CDNow 平台上某段时间的订单数据,定义加载数据的函数:
- 行3:数据源是文本文件,每列数据由多个空格分隔,因此我们使用 pd.read_table 方法,其中参数 sep 设置正则表达式"s " 表示1个或多个连续的空格
显示数据:
- 信息有用户id,日期,购买数量和购买金额
数据加载环节比较重要的3点:
- 清楚数据颗粒
- 缺失值处理
- 正确的字段类型
注意数据颗粒为"每天每一笔订单的信息"
因此,完全有可能出现同一天同一个用户多笔的记录:
现在看看数据表基本信息:
- 上方红框信息,表明共 6万多接近7万行的数据
- 下方红框信息,表明4个列没有缺失数据
- 绿色框,看到 user_id 与 date 的类型不对
转换类型的逻辑我写在加载数据的函数中:
- 行6:使用 pd.to_datetime 把非日期类型的字段转为日期,format 定义了提取规则
重新执行加载数据后即可
数据异常
数据分析并非拿到数据后马上做各种指标统计,做图表。如果数据本身出现逻辑错误,就算你的图表做得再漂亮也没用。
因此,pandas 为数据表做了一个方法,快速列出每一列的常用统计信息:
- DataFrame.describe 列出数值类的字段的统计信息,参数 include='all' ,让统计所有的列
- 我们特别要关注上图红框的列,能看出一些基本信息与问题
- 订单时间范围从1997年1月到1998年6月
- 金额最小值为0,这是赠品?
- 平均消费(金额)为35左右,但最大值有1286!
- 购买数据最大值为99!
- 数量列与金额列的中位数低于均值,可以大致得知大部分用户的消费与购买数量都在均值以下
看看购买数量高于70的记录:
- 原来那笔最高金额就在这里
这不能看出啥问题,看看这些用户平时的消费:
- 感觉与平时的消费习惯不符
从绝对数量和金额来看,有点与他们的消费习惯不符合。
不妨从单价上看看情况:
- 行6:通过订单金额除以数量,求出单价
- 从单价上看,2笔高购买数量的订单的单价都在各自用户的平均范围内
这里我们就暂且保留他们。
是否保留这些异常数据,可能需要更多其他维度的数据辅助判断。
不过在这里,你也可以独立思考其他的方式做判断,这通常需要结合业务知识。
比如,看看以上2笔数据的所在日期附近,是否有其他用户也出现购买数量上的明显提升。
这可能是那段时间搞促销,或某明星出新专辑,有粉丝大量购买。
这里不再展开
再看看订单金额为0的情况:
- 共80笔消费金额为0的记录
啰嗦的汇总代码
数据分析中的数据处理操作,大部分集中在分组统计中,因为需要变换数据颗粒做统计运算。
我们随意看几个例子。
"整体每月的销售额趋势":
- 眼瞎也能看出 97年4月的销售额出现大幅下降
销售额的下降有各种可能:
- 消费人数减少
- 消费金额减少(客单价)
- 一开始搞促销吸引大量顾客,促销后出现逆转
一个个来看看。
"那么每个月的消费人数走势如何呢":
- 注意数据颗粒是订单,统计人数时是不能直接对记录计数,如果同一个人在分组范围内出现多笔,应该视为一笔,因此需要对 user id 去重后再计数。这就是这里用 nunique 的原因
- 注意3月份的消费人数减少,但实际上本月的销售额是上升的
"看看我们的顾客的消费能力吧":
- 用销售额除以顾客人数,得到每个顾客的消费价格
- 可以看到,其实顾客的消费能力一直在上升
- 为什么3月的购买人数减少的情况下,销售额仍然有所提升?这里可以看出一些端倪。这时候出现了高价值的顾客
"那么是不是真的一开始搞促销才有大量客户来购买?":
- 也不是那么一回事,平均订单单价也是在下降(我们的数据没有商品信息,只能这么来看看)
分析过程不是本文重点,毕竟大家不一定对零售或电商行业有兴趣。
上面的过程展示了 pandas 的灵活和便捷。但是有没有发现这些代码比较难以表达业务。
比如,统计顾客人数的时候,我们用了两种不同的写法:
其次,客单价的计算表达也很奇怪:
- 金额除以 user_id !这也太傻了
如果你曾经使用过 BI 软件的话,你会发现这些软件的使用思维与我们上述的代码思维不太一样。
他们首先需要我们定义各种度量,一般是基于数据源的指标列的一种计算。
比如,我们求销售总额,只需要定义"使用 amount 字段,统计方式为 求和" 即可:
代码语言:javascript复制agg_消费总额 = {'amount': 'sum'}
其次我们也可以把常用的分组依据集中定义:
代码语言:javascript复制gk_按月 = pd.Grouper(key='date', freq='M')
现在统计销售额趋势是这样子:
不过,我们注意到,统计后的结果列名不受我们控制,因此,在 pandas 0.25版本追加了一个新的聚合方式,我们现在这样子定义度量:
代码语言:javascript复制agg_消费总额 = {'消费总额': pd.NamedAgg('amount', 'sum')}
- 字段的key 是结果的列名,value 是一个 pd.NamedAgg 对象,其中的参数分别是列名与统计方法
调用如下:
- 注意此时我们需要解包操作,把其中定义的字典解开为参数传入
现在可以一次性定义需要用到的指标度量:
其次把指标计算也定义出来:
- 有些计算如果觉得不希望每次统计都重新计算,你可以在数据源加载后立刻执行即可生成即可
现在重新执行刚刚的4个分析过程,就变得简单直白了。
"每月的销售额":
"每月消费人数":
"每月客单价":
- 行3:多个度量,只需要分别传入即可
"每月平均订单单价":
本次涉及的并非一些 pandas 的方法,而是使用 pandas 的一种模式,常用于数据探索分析。
本文讲解的度量值定义看似只能在单个项目中使用,实际只需要稍微思考一下,就能定义出跨项目通用的度量值统计方式。
这才是 pandas 的价值所在,否则我们直接使用其他的 BI 软件就可以了。
更多更详细的 pandas 高级应用,请关注我的 pandas 专栏,里面会有这些技巧的所有详细讲解和案例
最后
你会发现我源码中定义了其他的度量值,这会在后续更复杂的分析时用到,下次就会讲到。敬请关注!