Pandas批量处理Excel成绩单自动化与报错排查
用 Pandas 处理 Excel 成绩单,重点不是替代一两个公式,而是把多班、多科、多文件的重复处理固化成可复用脚本。案例覆盖 Python 3.9+ 环境、read_excel 读取、数据体检、清洗、总分/平均分/及格率、排名、cut 分箱、groupby/pivot_table、批量读写和常见报错排查。一、环境准备
Python 3.9 以上可用,安装时勾选 Add Python to PATH。Pandas 读写 .xlsx 依赖 openpyxl;只装 pandas 可能报 ValueError: Excel file format cannot be determined。安装命令:
pip install pandas openpyxl
验证:
import pandas as pd
print(pd.__version__)
PyCharm 在 Project Interpreter 安装包,VSCode 要选对解释器,否则会出现 ModuleNotFoundError 或 No module named pandas。
二、准备成绩数据
准备 3 个班文件:高一1班.xlsx、高一2班.xlsx、高一3班.xlsx。每张表第一行是列名,第二行开始是学生数据,字段为:学号、姓名、语文、数学、英语、物理、化学。这种“一行一个学生、一列一个科目”的宽表最适合 Pandas 分析。
三、读取与初步体检
import pandas as pd
df = pd.read_excel('高一1班.xlsx', sheet_name=0)
# 多 sheet 时显式指定,如 sheet_name='成绩表'
# 若首行是大标题、第二行才是字段名,可用 header=1
print(df.shape)
print(df.columns)
print(df.head())
print(df.info())
print(df.describe())
sheet_name=0 表示第一个工作表。shape 用来确认行数是否读漏,例如实际 35 人只读出 30 行,要检查空行或表尾残留。info() 看各列 Dtype 和非空数量;describe() 的 count、mean、min、max 是成绩健康度指标,最小值出现负数或最大值超过 150,应回 Excel 核对。
四、列类型与清洗
正常成绩列应为 int64 或 float64。如果某列是 object,常见原因是缺考填了“缺考”、录入 86.5 形成浮点、学号被 Excel 转成科学计数法。不要直接 astype(float),更稳妥的是:
df['数学'] = pd.to_numeric(df['数学'], errors='coerce')
能转数字的转数字,不能转的变成 NaN,再按考试规则决定按 0 分还是剔除。
缺失值要先判断业务含义。缺考通常不参与平均分,mean/sum 默认 skipna=True,会跳过 NaN。只有姓名和学号都为空的行才属于废数据:
df = df.dropna(subset=['学号', '姓名'])
不要直接整行 dropna,否则会误删“部分科目缺考但学生信息完整”的记录。算六科总分可直接按行求和:
df['总分'] = df.iloc[:, 2:8].sum(axis=1)
重复值按学号检查,姓名可能同名:
print(df.duplicated(subset=['学号']).sum())
df = df.drop_duplicates(subset=['学号'], keep='first')
keep='first' 只代表保留第一条;如果两条记录成绩不同,应人工核对原始材料再决定。
列名规范化同样关键。不同班级可能叫“语文”“语文成绩”“语文 ”,合并后会变成独立列,导致统计错误。可原样读入后 rename:
columns = ['学号', '姓名', '语文', '数学', '英语', '物理', '化学']
df = pd.read_excel('高一1班.xlsx', header=0, names=columns)
df = df.rename(columns={'语文成绩': '语文', '语文 ': '语文'})
names 会覆盖原列名,使用前先用 df.columns 确认实际列名,避免表头与数据行关系处理错。
五、常用成绩指标
score_cols = ['语文', '数学', '英语', '物理', '化学']
df['总分'] = df.sum(axis=1)
avg_scores = df.mean()
max_scores = df.max()
min_scores = df.min()
pass_rate = (df >= 60).mean()
axis=1 是沿列向右求和,得到每个学生总分;axis=0 是默认的按列统计。及格率利用 True 等于 1、False 等于 0,布尔序列的 mean 就是及格比例。
六、排名与等级划分
默认 rank() 是平均排名。580、580、570 会得到 1.5、1.5、3;中国式排名想让并列第一后下一位是第二,用 method='min':
df['总分排名'] = df['总分'].rank(ascending=False, method='min')
for col in score_cols:
df = df.rank(ascending=False, method='min')
rank 可能返回浮点,需要整数且确认没有 NaN 后再 astype(int)。等级划分用 cut:
import numpy as np
bins =
labels = ['D', 'C', 'B', 'A']
df['总分等级'] = pd.cut(df['总分'], bins=bins, labels=labels, right=True)
print(df['总分等级'].value_counts().sort_index())
right=True 表示左开右闭,(0,59] 为 D,(59,69] 为 C,(69,84] 为 B,(84,100] 为 A。总分可能超过 100 时,用 np.inf 作为上界,避免 cut 返回 NaN。
七、按班级分组与透视
class_avg = df_all.groupby('班级')['总分'].mean()
class_stats = df_all.groupby('班级').mean()
class_summary = df_all.groupby('班级')['总分'].agg(['mean', 'max', 'min', 'count'])
class_summary2 = df_all.groupby('班级').agg({'总分': ['mean', 'max'], '语文': 'mean', '数学': 'mean'})
pivot = pd.pivot_table(df_all, values='成绩', index='班级', columns='科目', aggfunc='mean')
pivot2 = df_all.groupby('班级').mean()
agg 列表里写什么函数名,输出列名就是什么,count 是各班非空人数。pivot_table 适合“一行一个学生一个科目成绩”的长表;如果原始数据是一行一个学生的宽表,直接 groupby 多列求均值即可,不必强行 reshape。
八、批量读取多个 Excel
import glob
import os
files = glob.glob('成绩文件夹/*.xlsx')
files =
df_list = []
for file in files:
temp = pd.read_excel(file)
class_name = os.path.basename(file).replace('.xlsx', '')
temp['班级'] = class_name
df_list.append(temp)
df_all = pd.concat(df_list, ignore_index=True)
glob 匹配所有 xlsx,~$ 开头的是 Excel 临时文件,必须过滤。文件名去掉扩展名后写入“班级”列,pd.concat 纵向拼接,ignore_index=True 让合并后的行索引从 0 重新编号。
九、导出到多个 Sheet
class_summary_reset = class_summary.reset_index()
with pd.ExcelWriter('成绩分析结果.xlsx') as writer:
df_all.to_excel(writer, sheet_name='总表', index=False)
class_summary_reset.to_excel(writer, sheet_name='班级汇总', index=False)
avg_scores.to_excel(writer, sheet_name='各科平均分')
ExcelWriter 作为上下文管理器,with 结束时自动保存关闭。groupby 结果是班级索引,想导出成普通列先用 reset_index();index=False 避免把行号写进 Excel。
十、常见问题排查
No module named pandas 分两种情况:没装,或装到了别的解释器。先确认当前解释器路径:
import sys
print(sys.executable)
然后把 pandas 安装到该环境。PyCharm 在 Settings 的 Project Interpreter 操作,VSCode 选择正确解释器。
中文列名和中文路径 Pandas 本身支持,不需要额外配置。若读取时报 UnicodeDecodeError,可升级 openpyxl:
pip install --upgrade openpyxl
read_excel 不接受 encoding 参数,只有 read_csv 才用 encoding;传了会报 TypeError。
成绩列是文本格式时,object 列求和可能变成字符串拼接或结果异常。先强制转数值,再看 dtype:
df['数学'] = pd.to_numeric(df['数学'], errors='coerce')
print(df.dtypes)
整数变成小数是因为列里混入 NaN,Pandas 为同时存数字和空值会把整列提升为 float64,85 显示为 85.0,这是特性不是 bug。缺考按 0 分处理时可:
df['语文'] = df['语文'].fillna(0).astype(int)
如果导出 Excel 后提示文件已损坏,优先检查 ExcelWriter 是否通过 with 正常关闭、目标文件是否正被 Excel 占用,以及 openpyxl 是否需要升级;不要在 writer 尚未关闭时手工打开结果文件。
整体流程可以固定为:环境准备、read_excel 读取、shape/info/describe 体检、缺失值/重复值/列名清洗、总分平均分及格率计算、rank 排名、cut 分箱、groupby/pivot_table 汇总、批量 glob 合并、ExcelWriter 多 Sheet 导出。数据变化后重跑脚本即可,适合成绩单以及其它结构化表格的重复自动化处理。
Re: Pandas批量处理Excel成绩单自动化与报错排查
这个整理挺扎实的,从环境准备、read_excel 读取、数据体检到清洗、指标、排名和分箱,整条线串得很清楚,对刚用 Pandas 处理成绩单的人很友好。我比较有共鸣的是列名规范化和缺考值处理这两块,不同班级表头多个空格或者叫“语文成绩”,合并后真的会多出列,统计直接对不上;用 to_numeric 配合 errors='coerce',再只按学号和姓名判断废数据,确实比直接整行 dropna 稳很多。rank 用 method='min' 处理并列排名、cut 用 np.inf 当上界避免 NaN,这些细节也很实用。期待后面 groupby、pivot_table 和批量读写部分,尤其多文件合并时怎么保留班级字段、怎么排掉表尾空行,这些坑挺常见的。Re: Pandas批量处理Excel成绩单自动化与报错排查
楼主这套流程挺完整的,尤其把 read_excel、数据体检、清洗和指标拆开讲,对刚接触 Pandas 处理成绩的人很友好。我自己也踩过类似坑,最容易出问题的往往不是总分公式,而是读进来之后的列名和类型。比如语文后面多个空格、表头前面多一行大标题,都会让后面的总分、排名和 groupby 对不上,所以先用 df.columns 和 df.info 看一眼确实很值。 缺考用 to_numeric(errors='coerce') 转成 NaN 再让 mean/sum 默认跳过,这比直接整行 dropna 稳很多,不会误删只缺某一科的学生。排名那里用 method='min' 也更符合学校里的习惯,不然并列第一后直接跳到第三,老师看着会别扭。cut 的 right=True 边界也要注意,59.5 这种分数落在哪一档,最好拿几条边界数据先跑一下确认。 另外如果后面要把多个班合并后再按班级分组,记得在读每个文件时先加一列班级,不然后面 groupby('班级') 会直接找不到列。批量跑之前先拿一个班跑通,再全校处理,输出前也留一份原始文件备份,出问题好回查。期待你把批量读写和透视表那部分也展开讲讲。Re: Pandas批量处理Excel成绩单自动化与报错排查
感谢分享,内容很系统,尤其是数据体检和清洗部分很贴合实际。read_excel 只装 pandas 会报格式无法识别这个坑我也遇到过,补上 openpyxl 后就正常了。缺考值用 to_numeric(errors='coerce') 转成 NaN,再根据业务决定按 0 分还是剔除,这比直接 astype(float) 稳妥很多;dropna 只针对学号和姓名,避免误删部分科目缺考的学生,这点很关键。排名用 method='min' 更符合中国式排名,580、580、570 得到 1、1、3,比默认平均排名直观。cut 分箱时上界用 np.inf 防止总分超界返回 NaN 也很实用,只是要注意 right=True 是左开右闭,60 分到底算不算及格取决于 bins 怎么写。批量多班处理时,我会在读取每个文件后先加一列班级名再 concat,不然后面 groupby('班级') 没有依据;另外合并前一定用 df.columns 核对列名,避免语文和语文成绩被当成两列。最后 groupby 那段好像没贴完,期待楼主继续补充 pivot_table 和批量读写、报错排查的完整示例。
页:
[1]