如何在Python中按科目成绩水平排序DataFrame生成学生科目排名?
基于学生分数生成科目排名的Python实现
问题描述
现有记录学生分数的DataFrame:
name | math | science | literature ---------------------------------- tom | 89 | 97 | 53 nick | 61 | 71 | 67 barry| 83 | 79 | 73
需要为每个学生按分数生成科目排名,得到如下结果:
name | subject1 | subject2 | subject3 ----------------------------------------------------- tom | science | math | literature nick | science | literature | math barry| math | science | literature
需求要点
- 现有手动对比分数的方法扩展性差,需支持最多10门科目的场景
- 分数相同时,字母序靠前的科目优先排前
更新(2022年8月20日)
使用推荐方案时出现报错:AttributeError: 'DataFrame' object has no attribute 'rank_axis'
解决方案
实现思路
对每行(每个学生)的科目数据,按「分数降序→科目名称升序」的规则排序,再将排序后的科目名拆分为多列即可,全程无需手动判断科目组合,可灵活适配任意科目数量。
代码实现
import pandas as pd # 初始化原始数据 df = pd.DataFrame({ 'name': ['tom', 'nick', 'barry'], 'math': [89, 61, 83], 'science': [97, 71, 79], 'literature': [53, 67, 73] }) # 设置name为索引,方便按单个学生处理数据 df_with_index = df.set_index('name') # 逐行排序:先按分数降序,分数相同则按科目名升序 sorted_subjects_per_student = df_with_index.apply( lambda row: row.sort_values( key=lambda x: (-x, x.name) ).index, axis=1 ) # 将排序后的科目列表转为多列,命名为subject1、subject2... result_df = sorted_subjects_per_student.apply(pd.Series).rename( columns=lambda idx: f'subject{idx + 1}' ) # 恢复name列为普通列 result_df = result_df.reset_index() print(result_df)
代码解释
- 索引设置:将
name设为索引,确保后续操作针对单个学生的所有科目数据 - 排序逻辑:
- 用
apply(axis=1)遍历每一行(学生) - 排序键
(-x, x.name)实现核心规则:-x将分数转为降序排序,x.name确保同分情况下字母序靠前的科目优先 - 提取排序后的科目名称(即Series的索引)
- 用
- 格式转换:将每行的科目名称列表拆分为独立列,命名为
subject1到subjectN,最后恢复name列。
报错修复
你遇到的AttributeError: 'DataFrame' object has no attribute 'rank_axis'是因为使用了pandas已废弃/移除的参数或方法。上述方案完全基于apply和sort_values实现,不存在版本兼容问题,可直接替代报错的方案。如果是其他代码导致的错误,需检查是否调用了已被淘汰的API,建议改用上述逐行排序的方式。
内容的提问来源于stack exchange,提问作者Stacker
相关产品推荐
相关产品推荐

