
本文详解如何利用自定义函数工厂与 DataFrame.groupby().agg() 一次性计算多个字段的指定分位数,并自动生成如 bell_q10、fish_q90 等语义化列名,兼顾代码简洁性、可读性与执行效率。
本文详解如何利用自定义函数工厂与 `dataframe.groupby().agg()` 一次性计算多个字段的指定分位数,并自动生成如 `bell_q10`、`fish_q90` 等语义化列名,兼顾代码简洁性、可读性与执行效率。
在 Pandas 中,groupby().agg() 是聚合统计的首选接口——它支持多函数、多列、命名输出,能将均值、中位数、计数等指标“一锅端”地高效计算。但默认不支持带参数的分位数(如 quantile(0.9)),导致用户常被迫拆解流程:先用 .quantile() 单独计算再拼接 DataFrame,既冗余又破坏链式表达。
核心解法:函数工厂(Function Factory)
通过闭包封装 q 参数,返回一个符合 agg() 要求的无参函数(接收 Series 并返回标量),即可无缝集成:
def quantile(q=0.5, **kwargs):
def f(series):
return series.quantile(q, **kwargs)
return f
# 直接用于 agg 的命名元组语法
result = df.groupby("dummy").agg(
bell_med=("bell", "median"),
bell_mean=("bell", "mean"),
fish_med=("fish", "median"),
fish_mean=("fish", "mean"),
bell_q10=("bell", quantile(0.1)),
bell_q90=("bell", quantile(0.9)),
fish_q10=("fish", quantile(0.1)),
fish_q90=("fish", quantile(0.9)),
)规模化扩展:字典推导式 + 双重解包
当需为多个列、多个分位点批量生成命名聚合时,推荐使用 **{...} 动态构造参数字典,避免硬编码:
# 定义基础统计 + 分位数组合
base_aggs = {
"bell_med": ("bell", "median"),
"bell_mean": ("bell", "mean"),
"fish_med": ("fish", "median"),
"fish_mean": ("fish", "mean"),
}
quantile_aggs = {
f"{col}_q{100*q:02n}": (col, quantile(q))
for q in [0.1, 0.25, 0.5, 0.75, 0.9] # 支持任意精度
for col in ["bell", "fish"]
}
result = df.groupby("dummy").agg(**base_aggs, **quantile_aggs)✅ 优势总结
-
零额外依赖:纯 Pandas 原生方案,无需
apply或pipe; -
列名可控:
f"{col}_q{100*q:02n}"精确生成bell_q10、fish_q95等可读标识; -
性能友好:
agg()内部优化执行路径,比循环调用.quantile()更高效; -
类型安全:返回
DataFrame,列顺序与定义一致,便于后续分析。
⚠️ 注意事项
-
quantile()在空组或全 NaN 列中返回NaN,建议前置检查df[col].notna().any(); - 若需插值(如
method="linear"),可通过**kwargs透传(例:quantile(0.9, method="midpoint")); - 多级分组(如
groupby(["dummy", "category"]))同样适用,无需修改函数逻辑。
至此,你已掌握一种兼具工程严谨性与表达力的分位数聚合范式——它让统计代码真正“言即所行”,告别拼接与重复。

















