一、groupby 基本使用
import pandas as pd
# 构建dataframe数据
df = pd.DataFrame({
'name': ['三国演义', '诛仙', '凡人修仙传', '活着', '射雕英雄传', '霸道总裁爱上我', '少年歌行', '少年白马醉春风', '神雕侠侣'],
'category': ['历史', '修真', '修真', '现实', '武侠', '都市', '仙侠', '仙侠', '武侠'],
'price': [33.5, 26, 32.8, 29, 37, 25.5, 30.2, 28, 38],
'num': [2, 1, 3, 6, 4, 8, 5, 3, 2]
})
# 分组操作,使用 by 参数指定分组列
group_df = df.groupby(by="category")
print(group_df) # <pandas.core.groupby.generic.DataFrameGroupBy object at 0x0000022484EE6610>
print(type(group_df)) # <class 'pandas.core.groupby.generic.DataFrameGroupBy'>
# DataFrame 经过分组之后得到 DataFrameGroupBy 对象
二、DataFrameGroupBy 的属性
# 循环打印 DataFrameGroupBy 的内容
for name, group in group_df:
# name 是所有分组的 key
print(name)
输出结果
仙侠
修真
历史
武侠
现实
都市
# 循环打印 DataFrameGroupBy 的内容
for name, group in group_df:
# group 是对应分组 key 的组内 DataFrame
print(group)
输出结果
name category price count
6 少年歌行 仙侠 30.2 5
7 少年白马醉春风 仙侠 28.0 3
name category price count
1 诛仙 修真 26.0 1
2 凡人修仙传 修真 32.8 3
name category price count
0 三国演义 历史 33.5 2
name category price count
4 射雕英雄传 武侠 37.0 4
8 神雕侠侣 武侠 38.0 2
name category price count
3 活着 现实 29.0 6
name category price count
5 霸道总裁爱上我 都市 25.5 8
三、groupby 的参数
def groupby(
self,
by=None, # 指定分组列,可以指定多列 [col1, col2,...]
axis: Axis | lib.NoDefault = lib.no_default, # 指定按行分组 0 或按列分组 1,默认 0
level: IndexLabel | None = None,
as_index: bool = True, # 返回对象是否以分组名作为索引,默认 True
sort: bool = True, # 是否对分组名进行排序,默认 True,关闭自动排序可以提高性能
group_keys: bool = True, # 默认 True,调用apply时,将分组的keys添加到索引中
observed: bool | lib.NoDefault = lib.no_default,
dropna: bool = True,
) -> DataFrameGroupBy:
四、分组后的聚合操作
1. 简单聚合
import pandas as pd
df = pd.DataFrame({
'name': ['三国演义', '诛仙', '凡人修仙传', '活着', '射雕英雄传', '霸道总裁爱上我', '少年歌行', '少年白马醉春风', '神雕侠侣'],
'category': ['历史', '修真', '修真', '现实', '武侠', '都市', '仙侠', '仙侠', '武侠'],
'price': [33.5, 26, 32.8, 29, 37, 25.5, 30.2, 28, 38],
'num': [2, 1, 3, 6, 4, 8, 5, 3, 2]
})
group_df = df.groupby(by="category")
# (1)count():统计数量
print(group_df.count())
# (2)sum():求和
print(group_df["price"].sum())
# (3)min()/max():取最小值/最大值
print(group_df["num"].max())
print(group_df["price"].min())
# (4)median():取中位数
print(group_df["price"].median())
# (5)mean():取平均值
print(group_df["num"].mean())
# (6)std():取标准差
print(group_df["price"].std())
# (7)var():取方差
print(group_df["num"].var())
2. agg
import pandas as pd
df = pd.DataFrame({
'name': ['三国演义', '诛仙', '凡人修仙传', '活着', '射雕英雄传', '霸道总裁爱上我', '少年歌行', '少年白马醉春风', '神雕侠侣'],
'category': ['历史', '修真', '修真', '现实', '武侠', '都市', '仙侠', '仙侠', '武侠'],
'price': [33.5, 26, 32.8, 29, 37, 25.5, 30.2, 28, 38],
'num': [2, 1, 3, 6, 4, 8, 5, 3, 2]
})
group_df = df.groupby(by="category")
# agg:针对不同的字段指定不同的聚合函数
agg_df = group_df.agg({
"price": ["max", "mean"],
"num": "sum"
})
print(agg_df)
结果展示
price num
max mean sum
category
仙侠 30.2 29.1 8
修真 32.8 29.4 4
历史 33.5 33.5 2
武侠 38.0 37.5 6
现实 29.0 29.0 6
都市 25.5 25.5 8
# 自定义列名
agg_df2 = group_df.agg(
my_col = ("price", "mean")
)
print(agg_df2)
结果展示
my_col
category
仙侠 29.1
修真 29.4
历史 33.5
武侠 37.5
现实 29.0
都市 25.5
3. transform
import pandas as pd
df = pd.DataFrame({
'name': ['三国演义', '诛仙', '凡人修仙传', '活着', '射雕英雄传', '霸道总裁爱上我', '少年歌行', '少年白马醉春风', '神雕侠侣'],
'category': ['历史', '修真', '修真', '现实', '武侠', '都市', '仙侠', '仙侠', '武侠'],
'price': [33.5, 26, 32.8, 29, 37, 25.5, 30.2, 28, 38],
'num': [2, 1, 3, 6, 4, 8, 5, 3, 2]
})
group_df = df.groupby(by="category")
# transform:会保持每一个分组的形状与原始数据形状相同
trans_df = group_df.transform("sum")
print(trans_df)
结果展示
name price num
0 三国演义 33.5 2
1 诛仙凡人修仙传 58.8 4
2 诛仙凡人修仙传 58.8 4
3 活着 29.0 6
4 射雕英雄传神雕侠侣 75.0 6
5 霸道总裁爱上我 25.5 8
6 少年歌行少年白马醉春风 58.2 8
7 少年歌行少年白马醉春风 58.2 8
8 射雕英雄传神雕侠侣 75.0 6
4. apply
import pandas as pd
df = pd.DataFrame({
'name': ['三国演义', '诛仙', '凡人修仙传', '活着', '射雕英雄传', '霸道总裁爱上我', '少年歌行', '少年白马醉春风', '神雕侠侣'],
'category': ['历史', '修真', '修真', '现实', '武侠', '都市', '仙侠', '仙侠', '武侠'],
'price': [33.5, 26, 32.8, 29, 37, 25.5, 30.2, 28, 38],
'num': [2, 1, 3, 6, 4, 8, 5, 3, 2]
})
group_df = df.groupby(by="category")
# apply:传入一个 lambda 函数表达式或一个函数作为操作运算
apply_df = group_df.apply(lambda x: x["name"] + "_abc")
print(apply_df)
结果展示
category
仙侠 6 少年歌行_abc
7 少年白马醉春风_abc
修真 1 诛仙_abc
2 凡人修仙传_abc
历史 0 三国演义_abc
武侠 4 射雕英雄传_abc
8 神雕侠侣_abc
现实 3 活着_abc
都市 5 霸道总裁爱上我_abc
5. filter
import pandas as pd
df = pd.DataFrame({
'name': ['三国演义', '诛仙', '凡人修仙传', '活着', '射雕英雄传', '霸道总裁爱上我', '少年歌行', '少年白马醉春风', '神雕侠侣'],
'category': ['历史', '修真', '修真', '现实', '武侠', '都市', '仙侠', '仙侠', '武侠'],
'price': [33.5, 26, 32.8, 29, 37, 25.5, 30.2, 28, 38],
'num': [2, 1, 3, 6, 4, 8, 5, 3, 2]
})
group_df = df.groupby(by="category")
# filter:传入一个 lambda 函数表达式或一个函数筛选 DataFrame 中的列或行
# 类似 SQL 中 groupby 后的 having 操作
filter_df = group_df.filter(func=lambda x: x["price"].mean() > 30)
print(filter_df)
结果展示
name category price num
0 三国演义 历史 33.5 2
4 射雕英雄传 武侠 37.0 4
8 神雕侠侣 武侠 38.0 2