
本文介绍如何在 pandas 中高效地为 dataframe 新增一列,表示每个 (group, subgroup) 组合基于其 value 总和的全局降序排名。核心思路是先分组求和、再排名、最后回填到原始数据。
本文介绍如何在 pandas 中高效地为 dataframe 新增一列,表示每个 (group, subgroup) 组合基于其 value 总和的全局降序排名。核心思路是先分组求和、再排名、最后回填到原始数据。
在数据分析中,常需对嵌套分组(如 group → subgroup)按某数值列的聚合结果(如 sum、mean)进行排序并赋予排名,再将该排名广播回原始行级数据。本例中,目标是:对每组 (group, subgroup) 计算 value 列的总和,然后根据该总和从大到小排名(最大和为第 1 名),并将该排名作为新列 rank 添加到原始 DataFrame 的每一行。
实现的关键在于三步链式操作:
-
分组聚合:使用
df.groupby(['group', 'subgroup'])['value'].sum()得到每个子组的总和; -
计算排名:对聚合结果调用
.rank(ascending=False)实现降序排名(默认method='average',遇并列取平均秩;如需最小秩可用method='min'); -
回填匹配:通过
merge()将带排名的子组摘要表与原始 DataFrame 基于group和subgroup列左连接。
完整代码如下:
import pandas as pd
df = pd.DataFrame({
"group": ["a", "a", "a", "a", "a", "b", "b", "b", "b", "b", "c"],
"subgroup": ["i","ii","i","ii","i","ii","i","ii","i","ii","ii"],
"value": [2, 4, 2, 3, 5, 1, 2, 4, 1, 5, 11]
})
# 生成 rank 列:按 (group, subgroup) 的 value 总和降序排名
rank_series = df.groupby(['group', 'subgroup'])['value'].sum().rank(ascending=False)
rank_df = rank_series.rename('rank').reset_index()
out = df.merge(rank_df, on=['group', 'subgroup'])
print(out)输出结果中,rank 列为浮点数(如 3.0),这是因为 rank() 默认返回 float64 类型。若需整数排名(例如处理无并列场景),可在合并后添加 .astype(int),但需注意:若存在并列(相同总和),rank(method='average') 会生成非整数(如 2.5),此时强制转 int 会截断,建议改用 method='min' 或 method='dense' 并配合 astype(int):
# 更鲁棒的整数排名(并列时取最小秩)
rank_series = df.groupby(['group', 'subgroup'])['value'].sum().rank(
method='min', ascending=False
).astype(int)此外,需注意:
-
merge()默认为 inner join,但因rank_df由df分组生成,所有(group, subgroup)组合均存在,故结果与原始行数一致; - 若原始数据含缺失的
(group, subgroup)组合(极少见),可显式指定how='left'提高可读性; - 此方法时间复杂度为 O(n),远优于循环或
apply,适用于大规模数据。
综上,该方案简洁、高效、可读性强,是 Pandas 中实现“分组聚合后排名回填”的标准范式。

















