Chapter 05

聚合与分组 groupby

掌握 group_by().agg() 分组聚合、一次做多个聚合、over 窗口表达式(无需分组即可组内计算)与 pivot 透视表。

5.1 group_by().agg() 基础

import polars as pl

df = pl.DataFrame({
    "city": ["北京", "上海", "北京", "上海", "北京"],
    "category": ["A", "A", "B", "B", "A"],
    "sales": [100, 200, 150, 50, 300],
})

# 按 city 分组,对 sales 求和
df.group_by("city").agg(
    pl.col("sales").sum()
)
# 北京 550 / 上海 250
顺序不保证

因为多线程并行,group_by 默认不保证输出行顺序。要稳定顺序传 maintain_order=True(略有性能代价),或在后面接 .sort()

5.2 多聚合一次完成

df.group_by("city").agg(
    pl.col("sales").sum().alias("total"),
    pl.col("sales").mean().alias("avg"),
    pl.col("sales").max().alias("peak"),
    pl.len().alias("cnt"),                     # 每组行数
    pl.col("category").n_unique().alias("n_cat"),
)

5.3 多列分组与组内表达式

agg 里的表达式作用于"每个分组内的子 DataFrame",因此可以做过滤、排序、取列表等复杂操作。

df.group_by(["city", "category"]).agg(
    pl.col("sales").sum(),
    # 只对组内 sales > 100 的求和
    pl.col("sales").filter(pl.col("sales") > 100).sum().alias("big_sum"),
    # 把组内 sales 收集成列表
    pl.col("sales").alias("sales_list"),
    # 组内最大 sales 对应的第一行 category
    pl.col("category").sort_by("sales", descending=True).first(),
)

5.4 常用聚合函数速查

sum / mean / median / min / max
基础统计聚合。缺失值默认被跳过。
std / var / quantile
标准差、方差、分位数(如 .quantile(0.9) 取 90 分位)。
pl.len()
每组的行数(现代写法,取代旧的 pl.count())。
n_unique
组内某列不同取值的个数,等价 SQL count(distinct)
first / last
组内第一/最后一个值,常配 sort_by 取"最大值对应的另一列"。
agg 中的 filter
在聚合前对组内数据先过滤,等价 SQL 的条件聚合 sum(x) filter (where ...)

5.5 over:窗口表达式

over 让你在不改变行数的前提下做组内聚合——每行都附上它所属组的聚合值。等价 SQL 的窗口函数 OVER (PARTITION BY ...)

# 给每行加上"本城市总销售额"和"占本城市比例"
df.with_columns(
    pl.col("sales").sum().over("city").alias("city_total"),
    (pl.col("sales") / pl.col("sales").sum().over("city"))
        .alias("share"),
    # 组内排名
    pl.col("sales").rank(descending=True).over("city").alias("rank"),
)
agg vs over

group_by().agg()折叠行(每组一行);over 保留所有行只附加组聚合值。要"每类平均值当新特征"用 over,要"每类汇总报表"用 agg。

5.6 pivot 透视表

# 行=city,列=category,值=sales 之和
df.pivot(
    values="sales",
    index="city",
    on="category",
    aggregate_function="sum",
)
# ┌──────┬─────┬─────┐
# │ city ┆ A   ┆ B   │
# ╞══════╪═════╪═════╡
# │ 北京 ┆ 400 ┆ 150 │
# │ 上海 ┆ 200 ┆ 50  │
# └──────┴─────┴─────┘

反向操作是 unpivot(宽表转长表),也叫 melt。

5.7 小结与下一步