Python案例:如何用Pandas做数据分组排名(附实战代码)
目录导读
- 为什么需要数据分组排名?
- Pandas分组排名核心函数:
groupby()+rank() - 6种不同排名方法详解(average、min、max、dense、first、ordinal)
- 实战案例:学生成绩分组排名
- 进阶技巧:多列分组、跨组排名、条件排名
- 常见错误与解决方案
- 问答环节:高频问题解答
为什么需要数据分组排名?
在日常数据分析中,我们经常需要按某个类别分组后,再对组内的数据进行排名。

- 按班级对学生的成绩进行排名
- 按部门对销售人员的业绩进行排名
- 按月份对产品销量进行排名
单纯使用df.sort_values()只能进行全局排名,而分组排名能反映出“组内竞争”的实际情况,这是数据分析中的高频需求。
Pandas分组排名核心函数:groupby() + rank()
Pandas提供了rank()方法,配合groupby()可以实现分组排名,核心语法:
df['排名'] = df.groupby('分组列')['排序列'].rank(method='排名方法', ascending=True/False)
分组列:按哪个字段分组(如班级、部门)排序列:对哪个数值字段排名(如成绩、销售额)method:排名方法(下文详述)ascending=True:升序排名(数值越小排名越前);False为降序
6种不同排名方法详解(附效果对比)
Pandas的rank()提供了6种排名方法,选择哪种取决于业务需求:
| method参数 | 效果说明 | 适用场景 |
|---|---|---|
'average'(默认) |
相同值取平均排名(如并列第2和第3,均排名2.5) | 学术统计、需要保留小数位 |
'min' |
相同值取最小排名(并列第2则均排第2) | 竞技排名,鼓励并列 |
'max' |
相同值取最大排名(并列第2则均排第3) | 严格排序,不鼓励并列 |
'dense' |
密集排名(并列后下一名紧接,如1,1,2) | 需要连续整数排名 |
'first' |
按出现顺序排名,相同值先出现者排名靠前 | 时间优先的场景 |
'ordinal' |
类似'first',但返回整数 |
与'first'几乎相同 |
演示代码:
import pandas as pd
data = {'班级': ['A','A','A','B','B','B'],
'成绩': [90, 85, 90, 88, 95, 88]}
df = pd.DataFrame(data)
for method in ['average','min','max','dense','first']:
df[method] = df.groupby('班级')['成绩'].rank(method=method, ascending=False)
print(df)
输出结果清晰展示了不同方法如何影响并列值的排名。
实战案例:学生成绩分组排名
场景:某学校有3个班级,需按班级对数学成绩进行降序排名,相同分数按语文成绩排名。
完整代码:
import pandas as pd
# 构造数据
data = {
'班级': ['A','A','A','A','B','B','B','C','C','C'],
'姓名': ['张三','李四','王五','赵六','孙七','周八','吴九','郑十','冯十一','陈十二'],
'数学': [92, 88, 92, 85, 90, 90, 88, 95, 87, 87],
'语文': [85, 90, 88, 82, 89, 85, 90, 82, 91, 86]
}
df = pd.DataFrame(data)
# 分组排名:按班级分组,先按数学降序,相同则按语文降序
df['数学排名'] = df.groupby('班级')['数学'].rank(method='dense', ascending=False)
# 处理并列:数学同分时按语文排名
df['综合排名'] = df.groupby('班级').apply(
lambda x: x[['数学','语文']].apply(tuple, axis=1).rank(method='dense', ascending=False)
).reset_index(level=0, drop=True)
print(df.sort_values(['班级','综合排名']))
结果解读:
- 班级A中,张三和王五数学同分92,但王五语文88>张三85,因此王五排名第1
- 班级C中,冯十一和陈十二数学同分87,冯十一语文91>陈十二86,因此冯十一排名第1
进阶技巧:多列排名与条件排名
1 多列分组排名
按两个维度分组(如年级+班级):
df.groupby(['年级','班级'])['成绩'].rank(ascending=False)
2 跨组全局排名
有时需要组内排名后,再结合全局数据计算,例如先分组排名,再筛选各组Top 3:
df['组内排名'] = df.groupby('班级')['成绩'].rank(method='dense', ascending=False)
top3 = df[df['组内排名'] <= 3]
3 条件分组排名
只对满足条件的行进行排名(如只排成绩合格的学生):
mask = df['成绩'] >= 60
df.loc[mask, '及格排名'] = df[mask].groupby('班级')['成绩'].rank(ascending=False)
常见错误与解决方案
错误1:KeyError: '分组列'
原因:分组列名拼写错误或不存在
解决:检查df.columns确认列名
错误2:排名结果出现NaN
原因:分组列存在缺失值,导致某些组无法排名
解决:先使用df.dropna(subset=['分组列'])清理
错误3:期望整数排名但得到小数
原因:使用了默认method='average'
解决:改用method='dense'或method='min'
错误4:排名顺序相反
原因:ascending参数设置错误
解决:降序排名用ascending=False
问答环节:高频问题解答
Q1:分组排名和全局排名有什么区别?
A:全局排名基于整个数据集排序(如全校排名),分组排名基于组内排序(如班级排名),Pandas中df['成绩'].rank()是全局排名,df.groupby('班级')['成绩'].rank()是分组排名。
Q2:如果数据有几十万行,分组排名性能如何?
A:Pandas的groupby+rank基于Cython优化,百万级数据可轻松处理,若超千万行,建议先sort_values再手动分组计算,或使用Dask。
Q3:如何实现类似“排名百分位数”(即百分比排名)?
A:在rank()中设置pct=True即可得到百分比排名(0~1之间)。
df['百分比排名'] = df.groupby('班级')['成绩'].rank(pct=True, ascending=False)
Q4:分组排名后,为什么索引会乱?
A:groupby()会保留原索引,如需重置,加.reset_index(drop=True)。
Q5:能否实现“窗口排名”(如只对近7天数据排名)?
A:可以先用rolling()计算时间窗口,再结合apply和rank(),但更推荐用sort_values后手动分组。
本文为原创内容,基于实际开发经验撰写,结合搜索引擎信息进行重组优化,希望能帮助您快速掌握Pandas分组排名技巧,如需转载,请保留出处。