当前位置:首页>python>用 Python 给班主任减负:30 秒算出"三好学生"名单

用 Python 给班主任减负:30 秒算出"三好学生"名单

  • 2026-09-30 17:33:23
用 Python 给班主任减负:30 秒算出"三好学生"名单

朋友发来一份 Excel:30 个学生,6 门主科 + 体育,要求"每科前 10 + 体育合格"才能评三好学生。

数据类似如下:

手动算?眼睛看瞎不算,关键是"并列第 10"这种边界情况处理起来还特别容易出错。

今天就用 Python 把它做成可复用的一键脚本,30 行搞定 👇

一、先把需求拆清楚

三好学生就两条硬条件:

① 每科成绩在班级前 10 名(6 门主科都要满足) ② 体育成绩合格

看起来简单,但有个隐藏的坑:第 10 名有并列怎么办?

举个真实场景👇

小蓝和李四政治都考 89 分,并列卡在第 10、第 11 名。

  • 严格口径:只取前 10 个名额,那第 11 名的小蓝被淘汰
  • 宽松口径:同分都算前 10

实际评选中,宽松口径更人性化——同分不同命会让家长投诉的。

二、技术选择

不需要数据库、不需要 Web 框架,pandas 一把梭:

  • pandas:读 Excel + 数据处理
  • openpyxl:写 Excel
  • Series.rank():排名判定,核心 API

三、数据准备

Excel 结构长这样👇

姓名    语文  数学  英语  物理  化学  政治  体育
老李    88    99   90    100   97    95   不合格
四妹    99    88   98    95    90    93   合格

主科是数值,体育是"合格/不合格"文本。

四、核心实现

4.1 主逻辑:判断一个学生是不是三好学生

import pandas as pd


defjudge_sanhao(df):
"""在三好学生判定后,给 df 加一列 '三好学生',返回新 df。"""
    subjects = ['语文', '数学', '英语', '物理', '化学', '政治']

# 用一个全是 True 的 Series 起步,每科 AND 一次
    in_top10 = pd.Series(True, index=df.index)
for subj in subjects:
# 关键:method='min' + ascending=False
# 分数越高排名越小,并列时取最小名次(宽松口径)
        rank = df[subj].rank(method='min', ascending=False)
        in_top10 &= rank <= 10

    pe_pass = df['体育'] == '合格'

    df = df.copy()
    df['三好学生'] = in_top10 & pe_pass
return df

4.2 入口

defmain():
    df = pd.read_excel('students.xlsx')
    result = judge_sanhao(df)

    sanhao = result[result['三好学生']]['姓名'].tolist()
    print(f'三好学生名单(共 {len(sanhao)} 人):')
for i, name in enumerate(sanhao, 1):
        print(f'  {i:>2}. {name}')

    result.to_excel('students_result.xlsx', index=False)


if __name__ == '__main__':
    main()

4.3 跑出来长这样

三好学生名单(共 4 人):
   1. 四妹
   2. 七妹
   3. 小蓝
   4. 关羽

五、关键技术点:pandas rank() 的 4 种 method

这个 API 是这次项目的灵魂,单独拎出来讲👇

df['score'].rank(method='?', ascending=False)

4 种 method 对比:

  • 'average':并列取平均名次(统计学分析常用)
  • 'min':并列都取最小名次 ✅ 本次用的
  • 'max':并列都取最大名次(严格淘汰用)
  • 'first':按出现顺序排(几乎用不到)

举个例子更直观。成绩 [100, 90, 90, 80],从高到低排:

  • average → [1, 2.5, 2.5, 4]
  • min → [1, 2, 2, 4] ✅
  • max → [1, 3, 3, 4]

我们的"宽松口径" = min:两个 89 分都给第 10 名,而不是一个第 10 一个第 11。

六、可视化验证:每科名次表

业务脚本光跑出名单不够,最好再把"每科名次"也打出来,方便核对边界 case:

defshow_rank_table(df):
    subjects = ['语文', '数学', '英语', '物理', '化学', '政治']
    rank_df = df[['姓名']].copy()
for subj in subjects:
        rank_df[f'{subj}_名次'] = df[subj].rank(method='min', ascending=False).astype(int)
        rank_df[subj] = df[subj]
    rank_df['体育'] = df['体育']
return rank_df

跑一下就能看到谁卡在边界👇

姓名   语文  数学  英语  物理  化学  政治  体育
关羽   3    8    8    10    1    1    合格
小蓝   7    1    8    4     5    10   合格
李四   4    5    3    6     3    10   不合格

一眼就能看到"小蓝 vs 李四"这个边界 case:分数相同、排名相同,但体育一合格一不合格,命运就分开了。

七、拓展:换需求怎么办?

把"评选规则"参数化,就能复用到其他场景:

defjudge(df, subjects, top_n, pass_col, pass_value):
    in_top = pd.Series(True, index=df.index)
for subj in subjects:
        rank = df[subj].rank(method='min', ascending=False)
        in_top &= rank <= top_n
return in_top & (df[pass_col] == pass_value)


# 例子 1:每科前 5 + 体育合格 = 优秀学生
df['优秀学生'] = judge(df, subjects, top_n=5, pass_col='体育', pass_value='合格')

# 例子 2:单科排名(数学竞赛选拔)
df['数学能手'] = judge(df, ['数学'], top_n=3, pass_col='体育', pass_value='合格')

这就是把"业务规则"和"技术实现"分离的好处——下学期改规则只改一行参数。

八、完整代码

把上面所有逻辑收个尾,30 行不到:

import pandas as pd


defjudge_sanhao(df):
    subjects = ['语文', '数学', '英语', '物理', '化学', '政治']
    in_top10 = pd.Series(True, index=df.index)
for subj in subjects:
        rank = df[subj].rank(method='min', ascending=False)
        in_top10 &= rank <= 10

    df = df.copy()
    df['三好学生'] = in_top10 & (df['体育'] == '合格')
return df


defmain():
    df = pd.read_excel('students.xlsx')
    result = judge_sanhao(df)

    sanhao = result[result['三好学生']]['姓名'].tolist()
    print(f'三好学生名单(共 {len(sanhao)} 人):')
for i, name in enumerate(sanhao, 1):
        print(f'  {i:>2}. {name}')

    result.to_excel('students_result.xlsx', index=False)


if __name__ == '__main__':
    main()

这个项目技术含量不高,但它是数据分析的典型缩影:

  • 业务规则 → 逻辑拆分:把"每科前 10"拆成"每科独立排名 + AND 组合"
  • API 选型:rank(method='min') 一行顶十行 if-else
  • 边界 case 显式化:并列、口径分歧,必须在代码里讲清楚
  • 可扩展性:参数化后能复用

下次遇到类似的"按分数/数量排名 + 多条件筛选"的需求(比如奖学金评选、绩效评级、KPI 达成),都可以拿这个模板改一改直接用。

— END —

如果觉得有帮助,欢迎点赞 + 在看 👏 有想看的主题,评论区留言,我安排 👇

为了能随时获取最新动态,大家可以动动小手将公众号添加到“星标⭐”哦,点赞 + 关注,用时不迷路!!!!

关注公众号:IT小本本 👇

用时不迷路!!

最新文章

随机文章