Pandas数据框如何按多列优先级排名并处理同分情况

来源:Java教程作者:马来西亚程序员头衔:程序员
导读:本期聚焦于马来西亚程序员创作的《Pandas数据框如何按多列优先级排名并处理同分情况》,敬请观看详情。想对数据框按多个列的优先级顺序排名,又担心出现同分怎么办。本文详细讲解Pandas中sort_values结合rank实现多列优先级排名的方法,深入分析method参数中average、min、max、first、dense五种同分处理策略的差异,并通过成绩排名案例演示降序、并列名次、组内排名等常见需求的完整代码写法,帮助你写出准确可复用的排名逻辑。

在实际的数据分析工作里,排名是一个高频需求。比如学生成绩表要按总分排名,总分相同的再按语文成绩区分先后;销售数据表要按销售额排名,销售额相同的再按订单量排序。Pandas提供了sort_values和rank两个核心方法,配合灵活的参数组合,可以轻松实现多列优先级排名以及各种同分处理策略。本文通过完整的案例代码,把这些技巧一次讲透。

Pandas数据框如何按多列优先级排名并处理同分情况

一、多列优先级排序的基础:sort_values

sort_values是Pandas中最常用的排序方法,它支持传入一个列名列表,列表中列的先后顺序就代表了优先级。排在前面的列优先比较,只有当前面的列值相同时,才会继续比较后面的列。这在语义上正好符合多列优先级排名的需求。

我们先构造一个学生成绩数据框来做演示,包含姓名、总分和语文三列:

import pandas as pd

df = pd.DataFrame({
    '姓名': ['张三', '李四', '王五', '赵六', '孙七'],
    '总分': [580, 580, 610, 550, 580],
    '语文': [120, 125, 130, 118, 122]
})
print(df)

现在要求按总分降序排名,总分相同时按语文成绩降序区分先后。只需要把两个列名按优先级传入sort_values,并分别指定升降序即可:

df_sorted = df.sort_values(
    by=['总分', '语文'],
    ascending=[False, False]
).reset_index(drop=True)
print(df_sorted)

这里有个细节值得注意:ascending参数接收一个列表,与by中的列一一对应,这样每一列都可以独立控制升序还是降序。另外排序后索引会保持原样,如果后续需要用位置访问,记得调用reset_index重置索引,这是一个容易被忽略但经常引发bug的地方。

二、rank方法与五种同分处理策略

排序只能给出先后顺序,如果要得到具体的名次数字,就需要用到rank方法。rank的核心难点在于同分怎么处理,它提供了method参数,包含五种策略,各有适用场景。

假设总分列中有三个人并列,我们逐一对比五种方法的结果差异:

df['average排名'] = df['总分'].rank(method='average', ascending=False)
df['min排名'] = df['总分'].rank(method='min', ascending=False)
df['max排名'] = df['总分'].rank(method='max', ascending=False)
df['first排名'] = df['总分'].rank(method='first', ascending=False)
df['dense排名'] = df['总分'].rank(method='dense', ascending=False)
print(df)

假设五个人的总分降序排列后是610、580、580、580、550,三个580占据了第2、3、4的位置。五种方法的结果分别是:

  • average:并列者取平均名次,三个580都得3,这也是默认值。体育比赛中并列名次常用这种方式。
  • min:并列者都取最靠前的名次,三个580都得2。这和SQL的RANK函数行为一致,是最常见的比赛排名方式,即并列第二,下一个人直接是第五。
  • max:并列者都取最靠后的名次,三个580都得4,下一个人是第五。
  • first:并列者按数据出现的先后顺序依次编号为2、3、4,完全不重复。适合需要强制唯一名次的场景,比如必须决出唯一名次的选拔。
  • dense:并列者名次相同,但下一个不同值紧接着编号,三个580都是2,550是3。这和SQL的DENSE_RANK一致,名次不会出现跳跃。

选哪种方法没有绝对对错,关键看业务语义。如果排名要用于评奖评优,通常用min或dense;如果要求名次唯一不重复,就用first。特别提醒,rank的ascending参数默认为True,也就是数值越小名次越靠前,做成绩排名时务必显式设置ascending=False,否则结果会完全颠倒。

三、多列优先级排名的完整实现方案

理解了排序和排名各自的能力之后,把两者组合起来就能实现多列优先级排名。核心思路是:先用sort_values按优先级排好序,再用rank的first方法或者基于位置生成名次列。

回到成绩表的例子,需求是总分优先、总分相同看语文、语文也相同则并列:

# 先按优先级排序,保证并列者的相对顺序确定
df = df.sort_values(
    by=['总分', '语文'], ascending=[False, False]
).reset_index(drop=True)

# 总分做min排名,总分相同者并列
df['名次'] = df['总分'].rank(method='min', ascending=False).astype(int)
print(df[['姓名', '总分', '语文', '名次']])

如果业务要求先看总分、再看语文、两者都相同才并列,可以先用排名元组的方式处理。一个实用技巧是把多列压缩成一个比较键,比如把次要列做微小的加权或者直接用groupby分组后再排名:

# 方案一:对多列组合做first排名,得到严格唯一的序号
df['唯一序号'] = df.sort_values(
    ['总分', '语文'], ascending=[False, False]
).index + 1

# 方案二:先按主要列排名,再用groupby在并列组内按次要列区分
df['总分名次'] = df.groupby('总分')['语文'] \
    .rank(method='first', ascending=False)

# 结合两者:总分并列时,语文高者序号靠前
def complex_rank(g):
    return g.rank(method='min', ascending=False)

df['综合名次'] = df['总分'].rank(method='min', ascending=False)
print(df)

再补充一个分组排名的场景。实际业务中经常需要在每个班级内部独立排名,而不是全年级一起排。这时用groupby加transform或apply即可:

df['班级内名次'] = df.groupby('班级')['总分'] \
    .rank(method='min', ascending=False).astype(int)

groupby之后调用rank会自动按组计算,返回值与原数据框行对齐,直接赋值为新列即可。这是比循环每个班级再拼接高效得多的写法。

四、常见坑与性能建议

第一个常见的坑是NaN值。rank默认有个na_option参数,取值为keep时NaN保持为NaN,为top或bottom时NaN会排在最前或最后。而sort_values里对应的参数是na_position。如果数据里有缺失值,两种方法的行为差异可能让排名结果不符合预期,建议在排名前明确处理缺失值策略。

第二个坑是数据类型问题。如果列是字符串类型的数字,排序和排名都会按字典序比较,比如9会比10大。排名前务必用astype转换成数值类型:

df['总分'] = pd.to_numeric(df['总分'], errors='coerce')

性能方面,sort_values底层使用稳定的排序算法,rank在大数据量下的时间复杂度是线性的,两者对于百万级别的数据都能在秒级完成。但如果需要反复对多列做复杂排名,建议提前把参与比较的列合并为单个可比较的键列,避免多次排序。此外,rank返回的是float类型,得到最终结果后用astype(int)转换,既节省内存也让输出更整洁。

总结一下,多列优先级排名用sort_values的列列表加ascending列表即可实现;名次数字用rank生成,method参数决定同分策略;分组排名交给groupby加rank;缺失值和类型问题在排名前处理好。掌握这几点,绝大多数排名需求都能干净利落地解决。

Pandas排名多列排序同分处理修改时间:2026-09-09 10:25:17

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260909/53330.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。