Pandas分组

Pandas 分组

1
2
import numpy as np
import pandas as pd

一、分组模式及其对象

1. 分组的一般模式

分组操作在日常生活中使用极其广泛,例如:

  • 依据性别分组,统计全国人口寿命的平均值
  • 依据季节分组,对每一个季节的温度进行组内标准化
  • 依据班级筛选出组内数学分数的平均值超过80分的班级

从上述的几个例子中不难看出,想要实现分组操作,必须明确三个要素:分组依据、数据来源、操作及其返回结果。同时从充分性的角度来说,如果明确了这三方面,就能确定一个分组操作,从而分组代码的一般模式即:

1
df.groupby(分组依据)[数据来源].使用操作
例如第一个例子中的代码就应该如下:
1
df.groupby('Gender')['Longevity'].mean()

现在返回到学生体测的数据集上,如果想要按照性别统计身高中位数,就可以如下写出:

1
2
df = pd.read_csv('../data/learn_pandas.csv')
df.groupby('Gender')['Height'].median()
Gender
Female    159.6
Male      173.4
Name: Height, dtype: float64

2. 分组依据的本质

前面提到的若干例子都是以单一维度进行分组的,比如根据性别,如果现在需要根据多个维度进行分组,该如何做?事实上,只需在groupby中传入相应列名构成的列表即可。例如,现希望根据学校和性别进行分组,统计身高的均值就可以如下写出:

1
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的分组依据都是直接可以从列中按照名字获取的,那如果希望通过一定的复杂逻辑来分组,例如根据学生体重是否超过总体均值来分组,同样还是计算身高的均值。

首先应该先写出分组条件:

1
condition = df.Weight > df.Weight.mean()

然后将其传入groupby中:

1
df.groupby(condition)['Height'].mean()
Weight
False    159.034646
True     172.705357
Name: Height, dtype: float64

【练一练】

请根据上下四分位数分割,将体重分为high、normal、low三组,统计身高的均值。 #### 【END】 从索引可以看出,其实最后产生的结果就是按照条件列表中元素的值(此处是TrueFalse)来分组,下面用随机传入字母序列来验证这一想法:

1
2
item = np.random.choice(list('abc'), df.shape[0])
df.groupby(item)['Height'].mean()
a    163.094828
b    163.874603
c    162.666129
Name: Height, dtype: float64

此处的索引就是原先item中的元素,如果传入多个序列进入groupby,那么最后分组的依据就是这两个序列对应行的唯一组合:

1
df.groupby([condition, item])['Height'].mean()
Weight   
False   a    159.334146
        b    159.257143
        c    158.543182
True    a    172.164706
        b    173.109524
        c    172.744444
Name: Height, dtype: float64

由此可以看出,之前传入列名只是一种简便的记号,事实上等价于传入的是一个或多个列,最后分组的依据来自于数据来源组合的unique值,通过drop_duplicates就能知道具体的组类别:

1
df[['School', 'Gender']].drop_duplicates()
School Gender
0 Shanghai Jiao Tong University Female
1 Peking University Male
2 Shanghai Jiao Tong University Male
3 Fudan University Female
4 Fudan University Male
5 Tsinghua University Female
9 Peking University Female
16 Tsinghua University Male
1
df.groupby([df['School'], df['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

3. Groupby对象

能够注意到,最终具体做分组操作时,所调用的方法都来自于pandas中的groupby对象,这个对象上定义了许多方法,也具有一些方便的属性。

1
2
gb = df.groupby(['School', 'Grade'])
gb
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x000001C1E7AB1408>

通过ngroups属性,可以得到分组个数:

1
gb.ngroups
16

通过groups属性,可以返回从$


Pandas分组
http://jingmengzhiyue.top/2023/10/01/第四章 分组/
作者
Jingmengzhiyue
发布于
2023年10月1日
许可协议