一、简介

sql中的分组语句group by很重要,pandas中也有类似的分组函数,即groupby,本文就主要介绍下它的用法。

二、groupby函数

和sql中的分组类似,pandas中的groupby函数也是先将df按照某个字段进行拆分,将相同属性分为一组;然后对拆分后的各组执行相应的转换操作;最后输出汇总转换后的各组结果

2.1 分组

首先要对一个df进行分组,即进行groupby函数,其参数如下:

df.groupby(
    by=None,
    axis=0,
    level=None,
    as_index: 'bool' = True,
    sort: 'bool' = True,
    group_keys: 'bool' = True,
    squeeze: 'bool' = <object object at 0x137ac9240>,
    observed: 'bool' = False,
    dropna: 'bool' = True,
)

其中,通过by指定要分组的字段,即根据哪个字段进行分组,可以是一个,也可以是多个;axis=0则是默认对列的值的属性进行分组,当然,也可以设为1,根据行的值的属性进行分组;as_index=True则是默认将分组列名作为输出的索引,如果想要将其作为一个字段添加到df中,可以用reset_index方法,具体见Python pandas基础——常用属性、方法和函数

现创建一个DataFrame作为示例(创建方法见Python pandas基础——创建Series、DataFrame):

data = {'name': ['apolo', 'apolo', 'apolo', 'adm', 'adm', 'adm', 'bolon', 'bolon', 'bolon', 
                  'ali', 'ali', 'ali', 'cathy', 'cathy', 'cathy', 'jack', 'jack', 'jack'],
         'subjects': ['math', 'english', 'chinese', 'math', 'english', 'chinese', 'math', 'english', 'chinese',
                      'math', 'english', 'chinese', 'math', 'english', 'chinese', 'math', 'english', 'chinese'],
         'grades' : [89, 78, 84, 89, 83, 85, 77, 88, 79, 89, 86, 83, 95, 90, 94, 78, 70, 80]
        }
df = pd.DataFrame(data)
df

输出:df记录了六名学生在math,English和Chinese上的考试成绩

    name	subjects	grades
0	apolo	math    	89
1	apolo	english	    78
2	apolo	chinese 	84
3	adm 	math    	89
4	adm 	english 	83
5	adm 	chinese 	85
6	bolon	math	    77
7	bolon	english 	88
8	bolon	chinese 	79
9	ali 	math    	89
10	ali 	english 	86
11	ali 	chinese 	83
12	cathy	math    	95
13	cathy	english  	90
14	cathy	chinese 	94
15	jack	math	    78
16	jack	english 	70
17	jack	chinese 	80

进行分组

df.groupby('name')

输出:输出的是一个DataFrameGroupBy对象,后续的操作都是对这个DataFrameGroupBy对象进行。

<pandas.core.groupby.generic.DataFrameGroupBy object at 0x165c0b1c0>

2.2 常用的操作函数

在得到DataFrameGroupBy对象后,我们就可以根据需要进行相应的转换操作。

2.2.1 直接加聚合函数

可以在DataFrameGroupBy对象后直接加mean(), sum(), min(), max()之类的聚合函数进行相应的操作。

求平均成绩

df.groupby('name').mean()

输出:可以看到输出了每个学生的平均成绩,结果是一个DataFrame,列索引是grades,行索引是学生的名字,name是行索引的名字。

	     grades
name	
adm 	85.666667
ali 	86.000000
apolo	83.666667
bolon	81.333333
cathy	93.000000
jack	76.000000

2.2.2 agg()

agg()的功能更加强大,除了可以向agg()函数中传入聚合函数外,也常用列表、字典等形式作为参数。

传入聚合函数

df.groupby('name').agg('mean')

输出:和直接加聚合函数的结果是一样的,但要注意的是,传入的是字符串,并不是真正的聚合函数。

	     grades
name	
adm 	85.666667
ali 	86.000000
apolo	83.666667
bolon	81.333333
cathy	93.000000
jack	76.000000

传入列表:求每个学生的平均成绩和最低成绩

df.groupby('name').agg(['mean', 'min'])

输出:结果是一个多索引的DataFrame,df.groupby('name').agg(['mean', 'min'])['grade']则是一个普通的DataFrame

            grades
            mean	min
name		
adm 	85.666667	83
ali 	86.000000	83
apolo	83.666667	78
bolon	81.333333	77
cathy	93.000000	90
jack	76.000000	70

2.2.3 apply()

apply()可以传入自定义的面向分组的函数。

求每个学生的数学平均成绩与英语平均成绩之差

df.groupby('name').apply(lambda x:x[x['subjects'] == 'math']['grades'].mean() - x[x['subjects'] == 'english']['grades'].mean())

输出:输出结果是一个Series

name
adm       6.0
ali       3.0
apolo    11.0
bolon   -11.0
cathy     5.0
jack      8.0
dtype: float64

2.2.4 transform

transform调用函数在每个分组上产生一个与原df相同索引的DataFrame,整体返回与原来对象拥有相同索引且已填充了转换后的值的DataFrame,相当于就是给原来的Dataframe添加了一列。

transform与agg和apply的区别相当于SQL中窗口函数和分组聚合的区别:transform并不对数据进行聚合输出,而只是对每一行记录提供了相应聚合结果;而后两者则是聚合后的分组输出。

df.groupby('name').transform('mean')

输出:结果是每个学生的平均成绩

     grades
0	83.666667
1	83.666667
2	83.666667
3	85.666667
4	85.666667
5	85.666667
6	81.333333
7	81.333333
8	81.333333
9	86.000000
10	86.000000
11	86.000000
12	93.000000
13	93.000000
14	93.000000
15	76.000000
16	76.000000
17	76.000000
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐