微信公众号:「Python读财」
若有问题或建议,请公众号留言
在平常的数据分析中,常常须要将数据根据某个(多个)字段划分为不一样的群体(group)进行分析,如电商领域将全国的总销售额根据省份进行划分,分析各省销售额的变化状况,社交领域将用户根据画像(性别、年龄)进行细分,研究用户的使用状况和偏好等。在Pandas中,上述的数据处理操做主要运用groupby
完成,这篇文章就介绍一下groupby
的基本原理及对应的agg
、transform
和apply
操做。python
为了后续图解的方便,采用模拟生成的10个样本数据,代码和数据以下:微信
company=["A","B","C"] data=pd.DataFrame({ "company":[company[x] for x in np.random.randint(0,len(company),10)], "salary":np.random.randint(5,50,10), "age":np.random.randint(15,50,10) } )
company | salary | age | |
---|---|---|---|
0 | C | 43 | 35 |
1 | C | 17 | 25 |
2 | C | 8 | 30 |
3 | A | 20 | 22 |
4 | B | 10 | 17 |
5 | B | 21 | 40 |
6 | A | 23 | 33 |
7 | C | 49 | 19 |
8 | B | 8 | 30 |
在pandas中,实现分组操做的代码很简单,仅需一行代码,在这里,将上面的数据集按照company
字段进行划分:app
In [5]: group = data.groupby("company")
将上述代码输入ipython
后,会获得一个DataFrameGroupBy
对象dom
In [6]: group Out[6]: <pandas.core.groupby.generic.DataFrameGroupBy object at 0x000002B7E2650240>
那这个生成的DataFrameGroupBy
是啥呢?对data
进行了groupby
后发生了什么?ipython
所返回的结果是其内存地址,并不利于直观地理解,为了看看group
内部到底是什么,这里把group
转换成list
的形式来看一看:函数
In [8]: list(group) Out[8]: [('A', company salary age 3 A 20 22 6 A 23 33), ('B', company salary age 4 B 10 17 5 B 21 40 8 B 8 30), ('C', company salary age 0 C 43 35 1 C 17 25 2 C 8 30 7 C 49 19)]
转换成列表的形式后,能够看到,列表由三个元组组成,每一个元组中,第一个元素是组别(这里是按照company
进行分组,因此最后分为了A
,B
,C
),第二个元素的是对应组别下的DataFrame
,整个过程能够图解以下:工具
总结来讲,groupby
的过程就是将原有的DataFrame
按照groupby
的字段(这里是company
),划分为若干个分组DataFrame
,被分为多少个组就有多少个分组DataFrame
。因此说,在groupby
以后的一系列操做(如agg
、apply
等),均是基于子DataFrame
的操做。理解了这点,也就基本摸清了Pandas中groupby
操做的主要原理。下面来说讲groupby
以后的常见操做。学习
聚合操做是groupby
后很是常见的操做,会写SQL
的朋友对此应该是很是熟悉了。聚合操做能够用来求和、均值、最大值、最小值等,下面的表格列出了Pandas中常见的聚合操做。spa
函数 | 用途 |
---|---|
min | 最小值 |
max | 最大值 |
sum | 求和 |
mean | 均值 |
median | 中位数 |
std | 标准差 |
var | 方差 |
count | 计数 |
针对样例数据集,若是我想求不一样公司员工的平均年龄和平均薪水,能够按照下方的代码进行:code
In [12]: data.groupby("company").agg('mean') Out[12]: salary age company A 21.50 27.50 B 13.00 29.00 C 29.25 27.25
若是想对针对不一样的列求不一样的值,好比要计算不一样公司员工的平均年龄以及薪水的中位数,能够利用字典进行聚合操做的指定:orm
In [17]: data.groupby('company').agg({'salary':'median','age':'mean'}) Out[17]: salary age company A 21.5 27.50 B 10.0 29.00 C 30.0 27.25
agg
聚合过程能够图解以下(第二个例子为例):
transform
是一种什么数据操做?和agg
有什么区别呢?为了更好地理解transform
和agg
的不一样,下面从实际的应用场景出发进行对比。
在上面的agg
中,咱们学会了如何求不一样公司员工的平均薪水,若是如今须要在原数据集中新增一列avg_salary
,表明员工所在的公司的平均薪水(相同公司的员工具备同样的平均薪水),该怎么实现呢?若是按照正常的步骤来计算,须要先求得不一样公司的平均薪水,而后按照员工和公司的对应关系填充到对应的位置,不用transform
的话,实现代码以下:
In [21]: avg_salary_dict = data.groupby('company')['salary'].mean().to_dict() In [22]: data['avg_salary'] = data['company'].map(avg_salary_dict) In [23]: data Out[23]: company salary age avg_salary 0 C 43 35 29.25 1 C 17 25 29.25 2 C 8 30 29.25 3 A 20 22 21.50 4 B 10 17 13.00 5 B 21 40 13.00 6 A 23 33 21.50 7 C 49 19 29.25 8 B 8 30 13.00
若是使用transform
的话,仅须要一行代码:
In [24]: data['avg_salary'] = data.groupby('company')['salary'].transform('mean') In [25]: data Out[25]: company salary age avg_salary 0 C 43 35 29.25 1 C 17 25 29.25 2 C 8 30 29.25 3 A 20 22 21.50 4 B 10 17 13.00 5 B 21 40 13.00 6 A 23 33 21.50 7 C 49 19 29.25 8 B 8 30 13.00
仍是以图解的方式来看看进行groupby
后transform
的实现过程(为了更直观展现,图中加入了company
列,实际按照上面的代码只有salary
列):
图中的大方框是transform
和agg
所不同的地方,对agg
而言,会计算获得A
,B
,C
公司对应的均值并直接返回,但对transform
而言,则会对每一条数据求得相应的结果,同一组内的样本会有相同的值,组内求完均值后会按照原索引的顺序返回结果,若是有不理解的能够拿这张图和agg
那张对比一下。
apply
应该是你们的老朋友了,它相比agg
和transform
而言更加灵活,可以传入任意自定义的函数,实现复杂的数据操做。在Pandas数据处理三板斧——map、apply、applymap详解
)中,介绍了apply
的使用,那在groupby
后使用apply
和以前所介绍的有什么区别呢?
区别是有的,可是整个实现原理是基本一致的。二者的区别在于,对于groupby
后的apply
,以分组后的子DataFrame
做为参数传入指定函数的,基本操做单位是DataFrame
,而以前介绍的apply
的基本操做单位是Series
。仍是以一个案例来介绍groupby
后的apply
用法。
假设我如今须要获取各个公司年龄最大的员工的数据,该怎么实现呢?能够用如下代码实现:
In [38]: def get_oldest_staff(x): ...: df = x.sort_values(by = 'age',ascending=True) ...: return df.iloc[-1,:] ...: In [39]: oldest_staff = data.groupby('company',as_index=False).apply(get_oldest_staff) In [40]: oldest_staff Out[40]: company salary age 0 A 23 33 1 B 21 40 2 C 43 35
这样便获得了每一个公司年龄最大的员工的数据,整个流程图解以下:
能够看到,此处的apply
和上篇文章中所介绍的做用原理基本一致,只是传入函数的参数由Series
变为了此处的分组DataFrame
。
最后,关于apply
的使用,这里有个小建议,虽说apply
拥有更大的灵活性,但apply
的运行效率会比agg
和transform
更慢。因此,groupby
以后能用agg
和transform
解决的问题仍是优先使用这两个方法,实在解决不了了才考虑使用apply
进行操做。
扫码关注公众号「Python读财」,第一时间获取干货,还能够加Python学习交流群!!