用groupby().agg()可一次性计算中位数和四分位数,需配合pd.Series.quantile指定0.25、0.5、0.75分位点,默认method='linear';避免apply()性能损耗,注意小样本插值差异及NaN自动处理。

用 groupby().agg() 一次性算中位数和四分位数
直接调 groupby().median() 只能得中位数,但四分位数(q1、q3)没现成方法。得靠 agg() 配合 numpy.quantile 或 pandas.Series.quantile 手动指定分位点。
注意:quantile 默认插值方式是 'linear',和 Excel 的 QUARTILE.INC 一致;若需和 R 的 quantile(type=7) 对齐,得显式传 interpolation='linear'(Pandas 2.1+ 已改名 method='linear')。
-
q1对应0.25,q3对应0.75,中位数就是0.5 - 传入函数时别写
lambda x: x.quantile(0.5)—— 这样会丢失组内索引对齐,优先用pd.Series.quantile或np.quantile - 若列含
NaN,quantile默认跳过,无需额外dropna=True
import pandas as pd
import numpy as np
df = pd.DataFrame({
'category': ['A', 'A', 'B', 'B', 'B'],
'value': [1, 3, 2, 4, 6]
})
result = df.groupby('category')['value'].agg([
('median', lambda x: x.quantile(0.5)),
('q1', lambda x: x.quantile(0.25)),
('q3', lambda x: x.quantile(0.75))
])
避免 apply() 带来性能陷阱
apply() 看起来灵活,但对大分组容易变慢——它把每组转成 Series 再逐个调函数,而 agg() 底层可向量化执行部分操作。
- 别写
df.groupby('cat').apply(lambda g: g['val'].quantile([0.25, 0.5, 0.75])),返回结构难对齐,且无法利用 Pandas 对quantile的优化 - 如果必须用
apply(比如要同时算多个统计量并打包成字典),记得加result_type='expand',否则返回的是Seriesofndarray,后续难处理 - 超过 10 万行、百级分组时,
agg比apply快 2–5 倍,差异明显
处理多列分组 + 多指标的命名冲突
当按多个列分组(如 groupby(['cat1', 'cat2'])),再对多个数值列(如 ['val1', 'val2'])同时算中位数和四分位数,列名会嵌套或重复,容易混淆。
立即学习“Python免费学习笔记(深入)”;
- 用
agg({col: [('q1', lambda x: x.quantile(0.25)), ...] for col in cols})显式控制每列的输出名 - 结果列名是
MultiIndex,取值时用result[('val1', 'q1')],不是result['val1_q1'] - 若想展平列名,加
result.columns = ['_'.join(col).strip() for col in result.columns.values],但注意下划线可能和原始列名冲突
警惕 quantile 在小样本下的行为差异
样本量 ≤ 3 时,不同插值法结果差异大。例如 [1, 2] 的 q1:linear 得 1.25,lower 得 1.0,higher 得 2.0。
- Pandas 默认
method='linear'(旧版叫interpolation),与大多数统计软件一致,但和某些 BI 工具默认不同 - 如果业务要求“取实际存在的值”,用
method='nearest',但要注意这可能导致q1 == median(如只有两个数时) - 建议在文档或注释里明确写清所用
method,尤其当结果要对接下游报表时
最易被忽略的是:分位数计算本身不检验数据分布,哪怕某组全是异常值,也会照常返回一个数字。做分组统计前,最好先用 describe() 或箱线图粗筛各组数据质量。


















