python处理数据的风骚操作[pandas 之 groupby&agg]

介绍

每隔一段时间我都会去学习、回顾一下python中的新函数、新操作。这对于你后面的工作是有一定好处的。

本文重点介绍了pandas中groupby、Grouper和agg函数的使用。这2个函数作用类似,都是对数据集中的一类属性进行聚合操作,比如统计一个用户在每个月内的全部花销,统计某个属性的最大、最小、累和、平均等数值。

其中,agg是pandas 0.20新引入的功能

groupby && Grouper

首先,我们从网上把数据下载下来,后面的操作都是基于这份数据的:

bash 复制代码
import pandas as pd

df = pd.read_excel("https://github.com/chris1610/pbpython/blob/master/data/sample-salesv3.xlsx?raw=True")
df["date"] = pd.to_datetime(df['date'])
df.head()

下面,我们统计'ext price'这个属性在每个月的累和(sum)值,[resample]只有在index为date类型的时候才能用:

scss 复制代码
df.set_index('date').resample('M')['ext price'].sum()
yaml 复制代码
date
2014-01-31    185361.66
2014-02-28    146211.62
2014-03-31    203921.38
2014-04-30    174574.11
2014-05-31    165418.55
2014-06-30    174089.33
2014-07-31    191662.11
2014-08-31    153778.59
2014-09-30    168443.17
2014-10-31    171495.32
2014-11-30    119961.22
2014-12-31    163867.26
Freq: M, Name: ext price, dtype: float64

进一步的,我们想知道每个用户每个月的sum值,那么就需要一个groupby了:

scss 复制代码
df.set_index('date').groupby('name')['ext price'].resample("M").sum()
yaml 复制代码
name                             date      
Barton LLC                       2014-01-31     6177.57
                                 2014-02-28    12218.03
                                 2014-03-31     3513.53
                                 2014-04-30    11474.20
                                 2014-05-31    10220.17
                                 2014-06-30    10463.73
                                 2014-07-31     6750.48
                                 2014-08-31    17541.46
                                 2014-09-30    14053.61
                                 2014-10-31     9351.68
                                 2014-11-30     4901.14
                                 2014-12-31     2772.90
Cronin, Oberbrunner and Spencer  2014-01-31     1141.75
                                 2014-02-28    13976.26
                                 2014-03-31    11691.62
                                 2014-04-30     3685.44
                                 2014-05-31     6760.11
                                 2014-06-30     5379.67
                                 2014-07-31     6020.30
                                 2014-08-31     5399.58
                                 2014-09-30    12693.74
                                 2014-10-31     9324.37
                                 2014-11-30     6021.11
                                 2014-12-31     7640.60
Frami, Hills and Schmidt         2014-01-31     5112.34
                                 2014-02-28     4124.53
                                 2014-03-31    10397.44
                                 2014-04-30     5036.18
                                 2014-05-31     4097.87
                                 2014-06-30    13192.19
                                                 ...   
Trantow-Barrows                  2014-07-31    11987.34
                                 2014-08-31    17251.65
                                 2014-09-30     6992.48
                                 2014-10-31    10064.27
                                 2014-11-30     6550.10
                                 2014-12-31    10124.23
White-Trantow                    2014-01-31    13703.77
                                 2014-02-28    11783.98
                                 2014-03-31     8583.05
                                 2014-04-30    19009.20
                                 2014-05-31     5877.29
                                 2014-06-30    14791.32
                                 2014-07-31    10242.62
                                 2014-08-31    12287.21
                                 2014-09-30     5315.16
                                 2014-10-31    19896.85
                                 2014-11-30     9544.61
                                 2014-12-31     4806.93
Will LLC                         2014-01-31    20953.87
                                 2014-02-28    13613.06
                                 2014-03-31     9838.93
                                 2014-04-30     6094.94
                                 2014-05-31    11856.95
                                 2014-06-30     2419.52
                                 2014-07-31    11017.54
                                 2014-08-31     1439.82
                                 2014-09-30     4345.99
                                 2014-10-31     7085.33
                                 2014-11-30     3210.44
                                 2014-12-31    12561.21
Name: ext price, Length: 240, dtype: float64

结果肯定是对的,但是不够完美。我们可以使用[Grouper]写得更加简洁:

less 复制代码
# df.set_index('date').groupby('name')['ext price'].resample("M").sum()
df.groupby(['name', pd.Grouper(key='date', freq='M')])['ext price'].sum()

结果和上面?一样,就不列出来了。

显然,这种写法多敲了很多次键盘,那么它的好处是啥呢?

首先,逻辑上更加直接,当你敲代码完成以上统计的时候,你首先想到的就是groupby操作,而set_index, resample好像不会立马想到。想到了groupby这个'动作'之后,你就会紧接着想按照哪个key来操作,此时

你只需要用字符串,或者Grouper把key定义好就行了。最后使用聚合函数,就得到了结果。所以,从人类的

思考角度看,后者更容易记忆。

另外,Grouper里的freq可以方便的改成其他周期参数(resample也可以),比如:

bash 复制代码
# 按照年度,且截止到12月最后一天统计ext price的sum值
df.groupby(['name', pd.Grouper(key='date', freq='A-DEC')])['ext price'].sum()
yaml 复制代码
name                             date      
Barton LLC                       2014-12-31    109438.50
Cronin, Oberbrunner and Spencer  2014-12-31     89734.55
Frami, Hills and Schmidt         2014-12-31    103569.59
Fritsch, Russel and Anderson     2014-12-31    112214.71
Halvorson, Crona and Champlin    2014-12-31     70004.36
Herman LLC                       2014-12-31     82865.00
Jerde-Hilpert                    2014-12-31    112591.43
Kassulke, Ondricka and Metz      2014-12-31     86451.07
Keeling LLC                      2014-12-31    100934.30
Kiehn-Spinka                     2014-12-31     99608.77
Koepp Ltd                        2014-12-31    103660.54
Kuhn-Gusikowski                  2014-12-31     91094.28
Kulas Inc                        2014-12-31    137351.96
Pollich LLC                      2014-12-31     87347.18
Purdy-Kunde                      2014-12-31     77898.21
Sanford and Sons                 2014-12-31     98822.98
Stokes LLC                       2014-12-31     91535.92
Trantow-Barrows                  2014-12-31    123381.38
White-Trantow                    2014-12-31    135841.99
Will LLC                         2014-12-31    104437.60
Name: ext price, dtype: float64

agg

从0.20.1开始,pandas引入了agg函数,它提供基于列的聚合操作。而groupby可以看做是基于行,或者说index的聚合操作。

从实现上看,groupby返回的是一个DataFrameGroupBy结构,这个结构必须调用聚合函数(如sum)之后,才会得到结构为Series的数据结果。

而agg是DataFrame的直接方法,返回的也是一个DataFrame。当然,很多功能用sum、mean等等也可以实现。但是agg更加简洁, 而且传给它的函数可以是字符串,也可以自定义,参数是column对应的子DataFrame

举个栗子?吧:

css 复制代码
df[["ext price", "quantity", "unit price"]].agg(['sum', 'mean'])

怎么样,是不是比使用

scss 复制代码
df[["ext price", "quantity"]].sum()
df['unit price'].mean()

简洁多了?

上例中,你还可以针对不同的列使用不同的聚合函数:

arduino 复制代码
df.agg({'ext price': ['sum', 'mean'], 'quantity': ['sum', 'mean'], 'unit price': ['mean']})

另外,自定义函数怎么用呢,也是so easy.

比如,我想统计sku中,购买次数最多的产品编号,可以这样做:

css 复制代码
# 这里的x是sku对应的column
get_max = lambda x: x.value_counts(dropna=False).index[0]
df.agg({'ext price': ['sum', 'mean'], 
        'quantity': ['sum', 'mean'], 
        'unit price': ['mean'], 
        'sku': [get_max]})

看起来很不协调,把它去掉:

css 复制代码
get_max = lambda x: x.value_counts(dropna=False).index[0]
# python就是灵活啊。
get_max.__name__ = "most frequent"
df.agg({'ext price': ['sum', 'mean'], 
        'quantity': ['sum', 'mean'], 
        'unit price': ['mean'], 
        'sku': [get_max]})

另外,还有一个小问题,那就是如果你希望输出的列按照某个顺序排列,可以使用collections的OrderedDict:

python 复制代码
get_max = lambda x: x.value_counts(dropna=False).index[0]
get_max.__name__ = "most frequent"
import collections

agg_dict = {
        'ext price': ['sum', 'mean'], 
        'quantity': ['sum', 'mean'], 
        'unit price': ['mean'], 
        'sku': [get_max]}
# 按照列名的长度排序。 OrderedDict的顺序是跟插入顺序一致的
df.agg(collections.OrderedDict(sorted(agg_dict.items(), key = lambda x: len(x[0]))))

测试新人可以学习《测试人的 Python 工具书》书籍《性能测试 JMeter 实战》书籍

相关推荐
大话性能4 小时前
教你一招,如何保护自己的 Python 代码?
测试
大话性能5 小时前
【Pycharm必学技巧 01】误删项目?一秒找回
测试
大话性能5 小时前
Python模块导入与路径管理
测试
大话性能6 小时前
Pycharm远程连接服务器的Python虚拟环境(Virtualenv)
测试
大话性能6 小时前
Python 对字节流处理模块Struct 详解
测试
MicrosoftReactor11 小时前
技术速递|如何使用 Playwright MCP 和 GitHub Copilot 调试 Web 应用
github·copilot·测试·playwright·mcp
艾莉丝努力练剑1 天前
【测试开发/测试】详解测试用例(下):详解设计测试用例的方法
linux·经验分享·测试用例·bug·测试
猫耳君1 天前
汽车网络安全 CyberSecurity ISO/SAE 21434 测试之三
安全·web安全·网络安全·汽车·测试·cyber·cybersecurity
艾莉丝努力练剑2 天前
【测试开发/测试】详解测试用例(上):测试用例、万能公式
运维·经验分享·测试开发·测试