import pandas as pd
import numpy as np
分类汇总 group by
指的是如下的一个或多个步骤的数据分组:
- Splitting: 根据某些标准将数据分成若干组。
- Applying: 将一个函数独立应用于每个组。
- Combining: 将结果合并到数据结构中。
其中,拆分步骤最简单。事实上,在许多情况下,我们可能希望将数据集分成若干组,并对这些组进行处理。
在应用步骤中,我们可能希望执行以下操作之一:
- Aggregation: 计算每组的汇总统计数据。例如计算每组的和
sum
以及平均值means
,或者数每组记录的个数。 - Transformation: 执行一些特定于组的计算,并返回一个相似的索引对象。例如获得每组排序后的第一个数据。
- Filtration: 根据评估为真或假的分组计算,丢弃一些分组。例如丢弃属于只有少数成员的组的数据,或者根据组和或平均值过滤数据。
分组
pandas 对象可以在其任意轴上拆分。分组的抽象定义是提供标签到组名的映射。分组需要创建 GroupBy
对象。
df = pd.DataFrame(
[
("bird", "Falconiformes", 389.0),
("bird", "Psittaciformes", 24.0),
("mammal", "Carnivora", 80.2),
("mammal", "Primates", np.nan),
("mammal", "Carnivora", 58),
],
index=["falcon", "parrot", "lion", "monkey", "leopard"],
columns=("class", "order", "max_speed"),
)
df
class | order | max_speed | |
---|---|---|---|
falcon | bird | Falconiformes | 389.0 |
parrot | bird | Psittaciformes | 24.0 |
lion | mammal | Carnivora | 80.2 |
monkey | mammal | Primates | NaN |
leopard | mammal | Carnivora | 58.0 |
按行分组。
df.groupby('class')
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x000001BC34299A10>
按多个字段分组。
df.groupby(['class', 'order'])
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x000001BC3427E710>
通常一张数据表每一行表示一条记录,每一列表示一个字段。因而分类汇总是针对字段,对每条记录(按行)进行分组。如果确实有按列进行分组的需求,将 DataFrame 对象转置即可。
应用与合并
汇总
df = pd.DataFrame(
{
"A": ["foo", "bar", "foo", "bar", "foo", "bar", "foo", "foo"],
"B": ["one", "one", "two", "three", "two", "two", "one", "three"],
"C": np.random.randn(8),
"D": np.random.randn(8),
}
)
df
A | B | C | D | |
---|---|---|---|---|
0 | foo | one | 0.106162 | -0.093786 |
1 | bar | one | -0.179389 | 2.213905 |
2 | foo | two | -0.190954 | 0.082038 |
3 | bar | three | 0.312979 | 1.034273 |
4 | foo | two | 1.052136 | -0.130627 |
5 | bar | two | -1.220164 | 1.215908 |
6 | foo | one | -0.926031 | -1.477368 |
7 | foo | three | 0.157087 | 1.622384 |
GroupBy
对象后索引 column 表示需要汇总的属性,会返回一个新的 GroupBy
对象。
grouped = df.groupby('A')[['C', 'D']]
求和
grouped.sum()
C | D | |
---|---|---|
A | ||
bar | -1.086574 | 4.464086 |
foo | 0.198399 | 0.002641 |
平均值
grouped.mean()
C | D | |
---|---|---|
A | ||
bar | -0.362191 | 1.488029 |
foo | 0.039680 | 0.000528 |
中位数
grouped.median()
C | D | |
---|---|---|
A | ||
bar | -0.179389 | 1.215908 |
foo | 0.106162 | -0.093786 |
最小值
grouped.min()
C | D | |
---|---|---|
A | ||
bar | -1.220164 | 1.034273 |
foo | -0.926031 | -1.477368 |
最大值
grouped.max()
C | D | |
---|---|---|
A | ||
bar | 0.312979 | 2.213905 |
foo | 1.052136 | 1.622384 |
标准差
grouped.std()
C | D | |
---|---|---|
A | ||
bar | 0.782748 | 0.635154 |
foo | 0.712226 | 1.100833 |
可以使用 agg
来使用任何可以进行汇总和统计的函数,包括用户自定义的函数。
grouped.agg(['sum', 'mean'])
C | D | |||
---|---|---|---|---|
sum | mean | sum | mean | |
A | ||||
bar | -1.086574 | -0.362191 | 4.464086 | 1.488029 |
foo | 0.198399 | 0.039680 | 0.002641 | 0.000528 |
次序
df = pd.DataFrame({
'Name': ['Jim', 'Jim', 'Jim', 'Pam', 'Pam'],
'Attempt': ['First', 'Second', 'Third', 'First', 'Second'],
'GRE Score': [298, 321, 314, 318, 330]
})
df
Name | Attempt | GRE Score | |
---|---|---|---|
0 | Jim | First | 298 |
1 | Jim | Second | 321 |
2 | Jim | Third | 314 |
3 | Pam | First | 318 |
4 | Pam | Second | 330 |
返回每个人最后一次 GRE 考试成绩:
df.groupby('Name')['GRE Score'].last()
Name
Jim 314
Pam 330
Name: GRE Score, dtype: int64
返回每个人第一次 GRE 考试成绩:
df.groupby('Name')['GRE Score'].first()
Name
Jim 298
Pam 318
Name: GRE Score, dtype: int64
使用 nth
可以返回第任意次 GRE 考试成绩:
df.groupby('Name')['GRE Score'].nth(1)
1 321
4 330
Name: GRE Score, dtype: int64
排序
给每次 GRE 考试都加上名次。
df['Rank'] = df.groupby('Name')['GRE Score'].rank(ascending=False).astype(int)
df
Name | Attempt | GRE Score | Rank | |
---|---|---|---|---|
0 | Jim | First | 298 | 3 |
1 | Jim | Second | 321 | 1 |
2 | Jim | Third | 314 | 2 |
3 | Pam | First | 318 | 2 |
4 | Pam | Second | 330 | 1 |
如要给每组数据都排序,建议先对原 DataFrame 对象排序,再分组。
df.sort_values('GRE Score', ascending=False).groupby('Name')['GRE Score'].first()
Name
Jim 321
Pam 330
Name: GRE Score, dtype: int64