概述
除了聚合、变换、过滤、应用外,
GroupBy对象还内置了许多快捷方法,用于查看每组头部/尾部数据、抽样、生成描述统计,以及对每组执行时间重采样与滚动窗口计算。
8.1 head()、tail()、sample()
这些方法返回每组前 n 行 / 后 n 行 / 随机抽样 n 行,结果仍为原始行数据。
import pandas as pd
df = pd.DataFrame({
"部门": ["A", "A", "A", "A", "B", "B", "B"],
"员工": ["张三", "李四", "王五", "赵六", "孙七", "周八", "吴九"],
"薪资": [8000, 9500, 8200, 9000, 12000, 11000, 13000],
})
# 每组前 2 行
df.groupby("部门").head(2)
# 每组后 1 行
df.groupby("部门").tail(1)
# 每组随机抽取 1 行
df.groupby("部门").sample(n=1, random_state=42)
# 每组按比例抽样
df.groupby("部门").sample(frac=0.5, random_state=42)
# head/tail 与 apply 对比
df.groupby("部门").apply(lambda x: x.head(2))注意
GroupBy.head(2)返回的索引可能不连续,需要时使用.reset_index(drop=True)。
8.2 describe()
describe()按组生成描述统计量:count、mean、std、min、25%、50%、75%、max。
# 单列描述统计
df.groupby("部门")["薪资"].describe()
# 多列描述统计
df.groupby("部门")[["薪资"]].describe()
# 传递百分位数
df.groupby("部门")["薪资"].describe(percentiles=[0.1, 0.9])
# 包含所有列(含 object 列)
df.groupby("部门").describe(include="all")输出为多层列索引,可通过
.loc或xs提取:desc = df.groupby("部门")["薪资"].describe() desc.loc["A", "mean"]
8.3 分组内 resample()
先分组,再对每组执行 时间重采样,用于「按部门分别统计月度/季度销量」等场景。
import numpy as np
# 模拟销售数据
sales = pd.DataFrame({
"部门": ["A", "A", "A", "A", "B", "B", "B", "B"],
"日期": pd.date_range("2024-01-01", periods=8, freq="D"),
"金额": np.random.randint(100, 500, 8),
})
# 必须先设置时间索引
sales = sales.set_index("日期")
# 按部门分组后按月重采样求和
sales.groupby("部门")["金额"].resample("M").sum()
# 更常见的写法:分组 + Grouper 重采样
sales.groupby(["部门", pd.Grouper(freq="M")])["金额"].sum()
# 重采样 + 多种聚合
sales.groupby("部门")["金额"].resample("M").agg(["sum", "mean", "count"])
# 分组后 resample 并重置索引
sales.groupby("部门")["金额"].resample("M").sum().reset_index()分组 + 重采样的索引顺序
结果为
MultiIndex:第一层是分组键,第二层是时间索引,可用.reset_index()展平。
8.4 分组内 rolling()
先分组,再对每组执行 滚动窗口计算,用于「各部门滚动 3 日均值」等场景。
# 模拟每日各部门销量
daily = pd.DataFrame({
"部门": ["A"] * 5 + ["B"] * 5,
"日期": list(pd.date_range("2024-01-01", periods=5, freq="D")) * 2,
"销量": [10, 15, 20, 25, 30, 100, 90, 80, 70, 60],
})
daily = daily.set_index("日期")
# 每组滚动 3 日均值
daily.groupby("部门")["销量"].rolling(3).mean()
# rolling + agg 多统计量
daily.groupby("部门")["销量"].rolling(3).agg(["mean", "sum", "max"])
# 滚动窗口 + 重置索引
daily.groupby("部门")["销量"].rolling(3).mean().reset_index()
# 指定 min_periods
daily.groupby("部门")["销量"].rolling(3, min_periods=1).mean()
# 与 transform 结合(将滚动均值广播回原表)
daily["滚动3日均值"] = daily.groupby("部门")["销量"].rolling(3, min_periods=1).mean().reset_index(level=0, drop=True)注意
分组 +
rolling()返回带MultiIndex的 Series,通常需要reset_index(level=0, drop=True)或.droplevel(0)后再赋回原 DataFrame。
相关笔记
- 上一节:分组与聚合-7-累积与排名
- 下一节:分组与聚合-9-特殊分组
- 延伸:十七、窗口计算、Grouper 对象