Pandas tricks 之 transform的用法
先来看一个实例问题。
如下销售数据中展现了三笔订单,每笔订单买了多种商品,求每种商品销售额占该笔订单总金额的比例。例如第一条数据的最终结果为:235.83 / (235.83+232.32+107.97) = 40.93%
。
后台回复“transform”获取本文全部代码和pdf版本。
思路一:
常规的解法是,先用对订单id分组,求出每笔订单的总金额,再将源数据和得到的总金额进行“关联”。最后把相应的两列相除即可。相应的代码如下:
1.对订单id分组,求每笔订单总额。由于有三个order
,因此最终会产生三条记录表示三个总金额。
2.数据关联合并
为了使每行都出现相应order的总金额,需要使用“左关联”。我们使用源数据在左,聚合后的总金额数据在右(反过来也可)。不指定连接key,则会自动查找相应的关联字段。由于是多行对一行的关联,关联上的就会将总金额重复显示多次,刚好符合我们后面计算的需要。结果如上图所示。
3.计算占比
有了前面的基础,就可以进行最终计算了:直接用商品金额ext_price
除以订单总额sum_price
。并赋值给新的列pct
即可。
4.格式调整
为了美观,可以将小数形式转换为百分比形式,自定义函数即可实现。
思路二:
对于上面的过程,pandas中的transform
函数提供了更简洁的实现方式,如下所示:
可以看到,这种方法把前面的第一步和第二步合成了一步,直接得到了sum_price
列。这就是transform
的核心:作用于groupby
之后的每个组的所有数据。可以参考下面的示意图帮助理解:
后面的步骤和前面一致。
这种方法在需要对多列分组的时候同样适用。
多列分组使用transform
为演示效果,我们虚构了如下数据,id,name,cls为维度列。
我们想求:以(id,name,cls)
为分组,每组stu的数量占各组总stu的比例。使用transform
处理如下:
同样再次计算占比和格式化,得到最终结果:
总结transform的用法
transform
函数的官方文档签名为:DataFrame.transform(func,axis=0,*args,**kwargs)
,表示调用func
函数进行转换,返回转换后的值,且返回值与原来的数据在相同的轴上具有相同的长度。func
可以是函数,字符串,列表或字典。具体可以参考官方文档:
https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.transform.html#pandas.DataFrame.transform。
transform
既可以和groupby
一起使用,也可以单独使用。
1.单独使用
此时,在某些情况下可以实现和apply
函数类似的结果。
2.与groupby一起使用
此时,transform函数返回与原数据一样数量的行,并将函数的结果分配回原始的dataframe。也就是说返回的shape是(len(df),1)
。本文开头的例子就是这样。而apply
函数返回聚合后的行数。例如:
transform
和apply
的另一个区别是,apply
函数可以同时作用于多列,而transform
不可以。下面用例子说明:
上图中的例子,定义了处理两列差的函数,在groupby之后分别调用apply
和transform
,transform并不能执行。如果不采用groupby
,直接调用,也会有问题,参见下面的第二种调用方式。
第三种调用调用方式修改了函数,transform
依然不能执行。以上三种调用apply的方式处理两列的差,换成transform
都会报错。
利用transform
填充缺失值
transform
另一个比较突出的作用是用于填充缺失值。举例如下:
在上面的示例数据中,按照name可以分为三组,每组都有缺失值。用平均值填充是一种处理缺失值常见的方式。此处我们可以使用transform对每一组按照组内的平均值填充缺失值。
小结:
transform
函数经常与groupby
一起使用,并将返回的数据重新分配到每个组去。利用这一点可以方便求占比和填充缺失值。但需要注意,相比于apply
,它的局限在于只能处理单列的数据。
- 剑指OFFER之最小的K个数(九度OJ1371)
- 剑指OFFER之数组中出现次数超过一半的数字(九度OJ1370)
- 如何成为一名10x的数据分析师?
- 肥料生产商全套三拼在手:拟融资1.47亿元
- 《外媒Cointelegraph专访Qtum量子链Jordan Earls》—浅谈目前Dapps的主要问题
- ASP .Net Core 2.0 修改默认端口
- 不满一岁的潜力股:2017年3D打印机器人盘点
- Reporting Service报表开发
- 不要信任云:这不只是安全的问题
- C#温故而知新—闲话.Net
- c# IO&&线程 打造 定时打开指定程序
- 前FDIC主席:比特币政策不应打击加密货币发展
- 任何人都不应该控制区块链供应链
- c# IO操作(带进度的文件复制器,读取文本文件的指定行)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Grafana使用zabbix自定义模板
- linux shell之变量的使用规则
- 第11期:压缩表
- grafana-zabbix插件安装和配置zabbix mysql
- grafana使用教程之API key
- Grafana使用教程之安装
- Java基础数据类型之包装类equals和==详解
- SCP不用密码传输文件
- Java 使用Collections.reverse对list集合进行降序排序
- Liquibase异常 mysql数据库 Cannot add foreign key constraint
- Linux获取文件最后修改时间
- Crontab脚本无法正常执行问题
- Python 输入时间字符串以分钟单位计算时间差
- Linux下执行bcp指令
- Python 处理时间差