点击上方"数据大宇宙",设为星标,干货资料,第一时间送到!
前言
身边有许多正在学习 Python 的 pandas 库做数据处理的小伙伴们都遇到一个问题——分组聚合。 网上很多这方面的资料,几乎都是列出一系列诸如 "xx方法不能用 Python 内置函数" 之类的规则。小伙伴都说记不住啊。 本文尝试把内部原理机制教会你,让你无需记忆这么多死板的规则即可灵活运用。
本文主要涉及的函数和要的:
- groupby
- apply
- agg
- transform
- 总结这些函数的特点,说明解决思路。
数据
本文大部分例子的数据,如下图定义:
分组
物以类聚,人以群分。数据处理时同样需要按类别分组处理,面对这样的高频功能需求, pandas 中提供 groupby 方法进行分组。
按 class 进行分组 如下图的代码:
- 17-19行,两行的写法是一样的。
- 注意一点,只是调用 groupby 方法,没有进行任何的处理,只返回一个迭代器。
- 行21,只有当你需要数据时,才会真正执行分组的运算
- 返回结果是一个元组(key,每个组的记录的DataFrame)。
你还可以传入具体的数据,他实际会按你传入的数据的值进行分组。
怎么处理这些组?
分组只是处理的第一步,一般来说,我们不应该用遍历去处理每个组。 在pandas中,为我们提供了一些聚合方法用于处理组数据。
apply
apply 只是一种对每个分组进行处理的通用方式。来看看流程动图:
- apply 方法中传入一个用于处理的方法。
- apply 会把每个分组以一个DataFrame的形式,传入处理方法的首个参数中。
- 因此,为什么很多文章说,apply 不能使用 python 内置函数,实际是 python 内置函数不能处理 DataFrame 而已。
- apply 在处理的最后一步,把每个分组的处理结果合并成一个 DataFrame 返回。
apply 中还可以传入自定义函数,比如我们希望用 value 减去 age 。如下:
- 注意一点,每个分组的处理结果同样可以是一个多行的 DataFrame 。
- 合并后,由于同个分组有多行数据,为了区别开来,合并结果的索引部分会带上数据源的索引。
有时候,自定义函数也需要额外的参数。 比如,希望返回 value 列减去指定值的新列
- 在调用 apply 时,传入命名参数值即可。
- 因为自定义首个参数是 DataFrame ,因此可以指定列表名,以此针对某列进行处理。
agg
agg 的处理流程与 apply 基本一致。当注意 agg 的处理函数的首个参数是 Series。
- 注意,处理函数是分别处理每个字段(Series)。
- 因此,不要在自定义函数中指定字段。
- 为什么很多文章说 agg 可以使用 python 内置函数,就是因为 python 内置函数可以处理 Series 。
下面是 agg 的自定义函数例子。
transform
当我们需要分组处理的中间结果,但不需要分组后的结果,则可以使用 transform 。 看其流程机制:
- transform 是为了保持结果的记录行数与原数据保持一致。
- transform 流程机制与 agg 几乎一样。区别在于最后的合并。
- 如果 transform 的处理函数返回是一个值,那么为了与原数据行数保持一致,因此会把组内的值在组内复制(广播)。
- transform 的处理函数还可以返回一个列(也就是有多行),但必须要求最终合并结果与原数据行数一致。
- 返回的结果不会出现分组的 key 字段。
看起来 transform 有不少规则需要记住。其实记住2点即可。
- transform 是为了保持结果的记录行数与原数据保持一致
- 处理函数的首个参数是字段(Series)
至于处理函数可以返回什么东西,完全是遵从点1。
特点
即使你学会了上述的知识点,但当你遇上问题时,还是会觉得无从入手。因为没有归纳他们的的特点。我们一起来看看。
groupby 分组本质上是为了按某个组别分别处理。而分组处理的结果无非3种:
- 结果会被压缩。比如原数据有100行2个组,分组后的结果就只有2行了。
- 结果保持原样。比如希望用每行的年龄减去所在组的平均年龄。处理结果还是100行,只是中间过程需要分组的计算结果。
- 结果部分被压缩。比如本文中的例子,求出每组的 top 2 的人选。
针对 apply,agg,transform 的特点可以归纳如下:
- 如果需要按组压缩结果,那么首选考虑 agg 。
- 如果需要保持原样,那么考虑 transform 和 apply 。
- 如果需要部分被压缩,比如 top n 问题,那么考虑使用 apply 。
例子
例子1:使用本文的例子数据,如果 value 存在缺失值则用组内均值填充。
- 从所需结果的情况分析,是完全保持原样,因此选用 transform 。
- 一般在使用 transform 时,在 groupby 之后指定一列。
- 自定义函数中可以很容易求得 value 的均值。
例子2:使用本文的例子数据,以 value 列为标准,得出每个分组的 top 2的人。
- 这是部分被压缩的需求,因此选用 apply 。
- 自定义函数中的首个参数是整块分组的数据,因此可以进行任意字段排序。然后进行选取返回即可。
最后
归纳好知识点,就能让自己少记住一些规则,灵活运用。
如果觉得本文对你有所帮助,记得关注、评论、转发、收藏噢~