import numpy as np
import pandas as pd
1.1 分组模式及其对象
1.1.1 分组的一般模式
分组操作在日常生活中使用极其广泛,例如:
依据性别性别分组,统计全国人口寿命寿命的平均值平均值
依据季节季节分组,对每一个季节的温度温度进行组内标准化组内标准化
依据班级班级筛选出组内数学分数数学分数的平均值超过80分的班级平均值超过80分的班级
从上述的几个例子中不难看出,想要实现分组操作,必须明确三个要素:分组依据分组依据、数据来源数据来源、操作及其返回结果操作及其返回结果。同时从充分性的角度来说,如果明确了这三方面,就能确定一个分组操作,从而分组代码的一般模式即:
df.groupby(分组依据)[数据来源].使用操作
例如第一个例子中的代码就应该如下:
df.groupby('Gender')['Longevity'].mean()
现在返回到学生体测的数据集上,如果想要按照性别统计身高中位数,就可以如下写出:
df = pd.read_csv(r'D:\item\TTclass\pandas\pandasgroup.csv')
df.groupby('Gender')['Height'].median()
结果:
Gender
Female 159.6
Male 173.4
1.1.2 分组依据的本质
前面提到的若干例子都是以单一维度进行分组的,比如根据性别,如果现在需要根据多个维度进行分组,该如何做?事实上,只需在groupby中传入相应列名构成的列表即可。例如,现希望根据学校和性别进行分组,统计身高的均值就可以如下写出:
df.groupby(['School', 'Gender'])['Height'].mean()
结果:
School Gender
Fudan University Female 158.776923
Male 174.212500
Peking University Female 158.666667
Male 172.030000
Shanghai Jiao Tong University Female 159.122500
Male 176.760000
Tsinghua University Female 159.753333
Male 171.638889
Name: Height, dtype: float64
目前为止,groupby的分组依据都是直接可以从列中按照名字获取的,那如果希望通过一定的复杂逻辑来分组,例如根据学生体重是否超过总体均值来分组,同样还是计算身高的均值。
首先应该先写出分组条件:
condition = df.Weight > df.Weight.mean()
然后将其传入groupby中:
df.groupby(condition)['Height'].mean()
结果:
Weight
False 159.034646
True 172.705357
Name: Height, dtype: float64
1.1.3 Groupby对象
能够注意到,最终具体做分组操作时,所调用的方法都来自于pandas中的groupby对象,这个对象上定义了许多方法,也具有一些方便的属性。
gb = df.groupby(['School', 'Grade'])
gb
通过ngroups属性,可以得到分组个数:
gb.ngroups #16
通过groups属性,可以返回从组名组名映射到组索引列表组索引列表的字典:
res = gb.groups
res.keys() # 字典的值由于是索引,元素个数过多,此处只展示字典的键
结果:
dict_keys([('Fudan University', 'Freshman'), ('Fudan University', 'Junior'), ('Fudan University', 'Senior'), ('Fudan University', 'Sophomore'), ('Peking University', 'Freshman'), ('Peking University', 'Junior'), ('Peking University', 'Senior'), ('Peking University', 'Sophomore'), ('Shanghai Jiao Tong University', 'Freshman'), ('Shanghai Jiao Tong University', 'Junior'), ('Shanghai Jiao Tong University', 'Senior'), ('Shanghai Jiao Tong University', 'Sophomore'), ('Tsinghua University', 'Freshman'), ('Tsinghua University', 'Junior'), ('Tsinghua University', 'Senior'), ('Tsinghua University', 'Sophomore')])
1.2 聚合函数
1.2.1 内置聚合函数
在介绍agg之前,首先要了解一些直接定义在groupby对象的聚合函数,因为它的速度基本都会经过内部的优化,使用功能时应当优先考虑。根据返回标量值的原则,包括如下函数:max/min/mean/median/count/all/any/idxmax/idxmin/mad/nunique/skew/quantile/sum/std/var/sem/size/prod。
idxmin()函数返回在请求轴上第一次出现最小值的索引。在任何索引中找到最小值的索引时,将排除所有NA /空值。
gb = df.groupby('Gender')['Height']
gb.idxmin()
结果:
Gender
Female 143
Male 199
Name: Height, dtype: int64
这些聚合函数当传入的数据来源包含多个列时,将按照列进行迭代计算:
gb = df.groupby('Gender')[['Height', 'Weight']]
gb.max()
Height |
Weight |
|
Gender |
||
Female |
170.2 |
63.0 |
Male |
193.9 |
89.0 |
1.2.2 agg方法
虽然在groupby对象上定义了许多方便的函数,但仍然有以下不便之处:
无法同时使用多个函数
无法对特定的列使用特定的聚合函数
无法使用自定义的聚合函数
无法直接对结果的列名在聚合前进行自定义命名
下面说明如何通过agg函数解决这四类问题:
【a】使用多个函数
当使用多个聚合函数时,需要用列表的形式把内置聚合函数对应的字符串传入,先前提到的所有字符串都是合法的。
gb = df.groupby('Gender')[['Height', 'Weight']]
gb.agg(['sum', 'idxmax', 'max'])
Height |
Weight |
|||||
sum |
idxmax |
max |