【Python学习笔记】Pandas实现Excel质检记录表初审、复核及质检统计

背景:

我有这样一个需要审核的飞书题目表,按日期分成多个sheet,有初审——复核——质检三个环节,这三个环节是不同的同学在作业,并且领到同一个题目的人选是随机的,也就是说,完成一道题的三个人之间完全是没有任何联系。在这里插入图片描述
在这里插入图片描述
我现在需要指定sheet表的范围,统计一段时间内各环节的数据指标:
初审同学,需要统计每个同学的做题总步数,有效做题步数,还有合格率。
复核同学,需要统计每个同学的做题总步数,有效做题步数,还有合格率。
质检同学,需要统计每个质检同学的检查题目数量。一行就是一道题目,所以质检同学只需要看写着他名字的共有几行就可以。

其中,有效做题步数是指质检同学检查后判定为正确的步数,比如一道题共25步,如果质检认为初审同学做对15步,复核同学做对18步,那么初审有效步数 = 15,复核有效步数 = 18.
初审合格率 = 总初审有效步数 / 初审做题总步数;
复核合格率= 总复核有效步数 / 复核做题总步数;

编写代码:

理清上述逻辑之后,下面的工作直接交给GPT:

import pandas as pddef analyze_qc_records(file_path, sheet_names):initial_stats = {}relabel_stats  = {}checker_counts = {}for sheet in sheet_names:df = pd.read_excel(file_path, sheet_name=sheet)for _, row in df.iterrows():# 初审init_name   = row.get('初审同学姓名')  # 取该行“初审同学姓名”,若是空值 (NaN) 则跳过。total_steps = row.get('单题步数', 0) or 0  # 当题目总步数(“单题步数”)缺失或为 NaN 时,设置为 0;否则读取数值。init_valid  = row.get('初审同学单题有效步数', 0) or 0  # 读取该行“初审同学单题有效步数”if pd.notna(init_name):st = initial_stats.setdefault(init_name, {'总步数': 0, '有效步数': 0})  # 用 setdefault 保证 initial_stats[姓名] 一定存在,并初始化为 { '总步数':0, '有效步数':0 }st['总步数']   += total_steps  # 每行累加“总步数”和“有效步数”st['有效步数'] += init_valid# 复核relabel_name  = row.get('复核同学姓名')relabel_valid = row.get('复核同学单题有效步数', 0) or 0if pd.notna(relabel_name):  # 如果不是缺失值st = relabel_stats.setdefault(relabel_name, {'总步数': 0, '有效步数': 0})  # 不管 relabel_name 之前在不在 relabel_stats 字典里,调用 setdefault 后,relabel_stats[relabel_name] 一定存在st['总步数']   += total_steps  # 总步数依然用当行的 total_steps —— 即复核同学也「认定」原题的总步数与初审相同st['有效步数'] += relabel_valid# 质检checker = row.get('质检同学姓名')if pd.notna(checker):  # 每遇到一行有“质检同学姓名”,就让对应姓名的计数 +1checker_counts[checker] = checker_counts.get(checker, 0) + 1# 构建 DataFrame(保留数值合格率)initial_df = pd.DataFrame([{'初审同学姓名': name,'总步数': stats['总步数'],'有效步数': stats['有效步数'],'合格率': stats['有效步数'] / stats['总步数'] if stats['总步数'] else 0}  # 用“有效步数 ÷ 总步数” 得到一个 0–1 之间的小数;若总步数为 0 则直接赋 0,避免除零错误。for name, stats in initial_stats.items()])relabel_df = pd.DataFrame([{'复核同学姓名': name,'总步数': stats['总步数'],'有效步数': stats['有效步数'],'合格率': stats['有效步数'] / stats['总步数'] if stats['总步数'] else 0}for name, stats in relabel_stats.items()])checker_df = pd.DataFrame([{'质检同学姓名': name, '检查题目数': count}for name, count in checker_counts.items()])# 百分比格式化initial_df['合格率'] = initial_df['合格率'].map(lambda x: f"{x:.2%}")relabel_df['合格率'] = relabel_df['合格率'].map(lambda x: f"{x:.2%}")# 排序 初审/复核 按姓名字母序;质检按检查量从高到低。initial_df = initial_df.sort_values(by='初审同学姓名').reset_index(drop=True)relabel_df = relabel_df.sort_values(by='复核同学姓名').reset_index(drop=True)checker_df = checker_df.sort_values(by='检查题目数', ascending=False).reset_index(drop=True)return initial_df, relabel_df, checker_dfif __name__ == '__main__':# 示例:读取文件并指定 sheet 范围file_path = '目录/质检记录.xlsx'xls = pd.ExcelFile(file_path)# 假如想统计第 1 到第 3 张 sheet(索引从 0 开始)selected_sheets = xls.sheet_names[0:3]init_df, relabel_df, checker_df = analyze_qc_records(file_path, selected_sheets)# 打印结果print("初审同学统计:")print(init_df)print("\n复核同学统计:")print(relabel_df)print("\n质检同学统计:")print(checker_df)# 如需导出到 Excel:with pd.ExcelWriter('目录/质检统计结果.xlsx') as writer:init_df.to_excel(writer, sheet_name='初审统计', index=False)relabel_df.to_excel(writer, sheet_name='复核统计', index=False)checker_df.to_excel(writer, sheet_name='质检统计', index=False)print("统计已导出到 质检统计结果.xlsx")

输出结果:

在这里插入图片描述
结果会直接写入XLSX文件保存。
并且初审/复核 按姓名字母序排列;质检按检查量从高到低排序。
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
截至目前圆满实现了我的需求,完美!!

需要注意的点&容易困惑的代码片段:

1.飞书必须导出为XLSX

因为CSV没有多个sheet,无法实现跨多张表统计。如果导出成了CSV,你会惊喜地发现只剩下第一张表,后面的数据全丢了。
在这里插入图片描述
下载为CSV的后果…
在这里插入图片描述

2.if pd.notna(relabel_name),pd.notna是什么意思?

pd.notna(…) 的作用:
功能:判断一个值是否 不是 “缺失值”(NaN / None / NaT 等)。

返回:布尔值——如果传入的 relabel_name 既不是 NaN 也不是 None,则返回 True;否则返回 False。

为什么要用:在读取 Excel 时,空单元格会被 Pandas 识别为 NaN。只有当姓名字段确实有值时,才要执行后续的统计操作;如果是空的,就跳过这一行,避免在字典里注册一个空字符串或 NaN 作为键。

示例代码:

import pandas as pdprint(pd.notna("Alice"))   # True,说明 "Alice" 是个有效字符串
print(pd.notna(None))      # False,说明 None 是缺失值
print(pd.notna(float('nan')))  # False,NaN 也是缺失值

这点确实很好用,有的同学填表容易漏项,没有把信息写全,留出一些空值在表里,会导致统计数据出现异常,非常的棘手。

3.dict.setdefault(key, default) 的用法?

所属类型:这是 Python 内置字典 (dict) 的一个方法。

功能:
如果字典中已经有了 key,就直接返回 dict[key];
如果没有 key,就先把 key: default 这对键值对插入字典,然后返回这个 default。

为什么要用:
这样写可以保证:不管 relabel_name 之前在不在 relabel_stats 字典里,调用 setdefault 后,relabel_stats[relabel_name] 一定存在,且是一个形如 {‘总步数’: 0, ‘有效步数’: 0} 的初始结构。

之后就可以安心地做 st[‘总步数’] += total_steps、st[‘有效步数’] += relabel_valid这样步数统计的操作,不用每次都写一大段 “如果 key 不在,就先赋值” 的逻辑

示例代码:

d = {}
x = d.setdefault('张三', {'总步数': 0, '有效步数': 0})
# 这时 d == {'张三': {'总步数': 0, '有效步数': 0}}
# 变量 x 就是 {'总步数': 0, '有效步数': 0}# 再次调用
y = d.setdefault('张三', {'总步数': 100, '有效步数': 50})
# 因为 '张三' 已存在,d 不变,y 仍是原来的 {'总步数': 0, '有效步数': 0}print(d)  # {'张三': {'总步数': 0, '有效步数': 0}}

那么回到我们解决问题的代码:在这里插入图片描述
结合第二点,这段代码的作用是:
先用 pd.notna 确保 relabel_name 真有值。
再用 setdefault 拿到或初始化统计结构,省去了手写“键不存在就先赋值”的繁琐。
最后在 st 上累加步数,就完成了该同学在“初审”或者”复核“环节的统计。
这样写既简洁又安全,不用担心 KeyError 或把空姓名也算进去。

4.for name, stats in initial_stats.items() ])这个stats是什么?

initial_stats 是你在前面遍历所有行时累积的一个字典,形如:

{"张三": {"总步数": 120, "有效步数": 110},"李四": {"总步数": 95,  "有效步数": 90},...
}

initial_stats.items() 会返回一个由 (key, value) 对组成的可迭代对象,这里 key 就是每个同学的姓名,value 就是对应的那个小字典(包含 “总步数” 和 “有效步数” 两个字段)

所以在列表推导里:

for name, stats in initial_stats.items()

name —— 对应同学姓名(例如 “张三”)
stats —— 对应该同学的那个子字典(例如 {“总步数”: 120, “有效步数”: 110})

接下来你就可以用 stats[‘总步数’]、stats[‘有效步数’] 来取出这两个值,计算合格率:

'合格率': stats['有效步数'] / stats['总步数'] if stats['总步数'] else 0

如果觉得 stats 这个名字不直观,也可以任意改成别的,比如 data、counts、vals,逻辑完全一样:它只是“每个同学对应的那份统计数据”的一个变量名。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/79472.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

守护进程编程、GDB调试以及外网连接树莓派

目录 一、什么是守护进程以及如何创建守护进程1. 什么是守护进程?2. 如何创建守护进程? 二、什么是GDB调试以及如何用GDB命令调试C程序1. 什么是GDB?2. 如何用GDB命令调试C程序? 三、外网访问树莓派 一、什么是守护进程以及如何创…

Logisim数字逻辑实训——计数器设计与应用

4位递增计数器 六进制计数器 十进制计数器 六十进制计数器 二十四进制计数器 计时器

发现“横”字手写有难度,对比两个“横”字

我发现手写体“横”字“好看”程度&#xff0c;难以比得上印刷体&#xff1a; 两个从方正简体启体来的“横”字&#xff1a; 哪个更好看&#xff1f;我是倾向于左边一点。 <div style"transform: rotate(180deg); display: inline-block;"> 左边是我从方正简…

ubuntu 向右拖动窗口后消失了、找不到了

这是目前单显示器的设置&#xff0c;因为实际只有1个显示器&#xff0c;之前的设置如下图所示&#xff0c;有2个显示器&#xff0c;一个主显示器&#xff0c;一个23寸的显示器 ubuntu 22.04 系统 今天在操作窗口时&#xff0c;向右一滑&#xff0c;发现这个窗口再也不显示了、找…

专精特新政策推动,B端UI设计如何赋能中小企业创新发展?

在当前数字化转型浪潮下&#xff0c;专精特新政策为中小企业提供了强大的支持&#xff0c;助力其在细分领域实现专业化、精细化、特色化和创新化发展。B端UI设计作为提升企业数字化产品用户体验和工作效率的重要手段&#xff0c;能够有效赋能中小企业创新发展。本文将探讨专精特…

梯度下降代码

整体流程 数据预处理:标准化->加一列全为1的偏置项 训练:梯度下降,将数学公式转换成代码 预测 模型代码 import numpy as np# 标准化函数&#xff1a;对特征做均值-方差标准化 # 返回标准化后的特征、新数据的均值和标准差&#xff0c;用于后续预测def standard(feats…

RAG 实战|用 StarRocks + DeepSeek 构建智能问答与企业知识库

文章作者&#xff1a; 石强&#xff0c;镜舟科技解决方案架构师 赵恒&#xff0c;StarRocks TSC Member &#x1f449; 加入 StarRocks x AI 技术讨论社区 https://mp.weixin.qq.com/s/61WKxjHiB-pIwdItbRPnPA RAG 和向量索引简介 RAG&#xff08;Retrieval-Augmented Gen…

从零开始学A2A一:A2A 协议的高级应用与优化

A2A 协议的高级应用与优化 学习目标 掌握 A2A 高级功能 理解多用户支持机制掌握长期任务管理方法学习服务性能优化技巧 理解与 MCP 的差异 分析多智能体场景下的优势掌握不同场景的选择策略 第一部分&#xff1a;多用户支持机制 1. 用户隔离架构 #mermaid-svg-Awx5UVYtqOF…

【C++】入门基础【上】

目录 一、C的发展历史二、C学习书籍推荐三、C的第一个程序1、命名空间namespace2、命名空间的使用3、头文件<iostream>是干什么的&#xff1f; 个人主页<—请点击 C专栏<—请点击 一、C的发展历史 C的起源可以追溯到1979年&#xff0c;当时Bjarne Stroustrup(本…

1panel第三方应用商店(本地商店)配置和使用

文章目录 引言资源网站实战操作说明 引言 1Panel 提供了一个应用提交开发环境&#xff0c;开发者可以通过提交应用的方式将自己的应用推送到 1Panel 的应用商店中&#xff0c;供其他用户使用。由此衍生了一种本地应用商店的概念&#xff0c;用户可以自行编写应用配置并上传到自…

Evidential Deep Learning和证据理论教材的区别(主要是概念)

最近终于彻底搞懂了Evidential Deep Learning&#xff0c;之前有很多看不是特别明白的地方&#xff0c;原来是和证据理论教材&#xff08;是的&#xff0c;不只是国内老师写的&#xff0c;和国外的老师写的教材出入也比较大&#xff09;的说法有很多不一样&#xff0c;所以特地…

text-decoration: underline;不生效

必须得纪念一下&#xff0c;在给文本加下划线时&#xff0c;发现在win电脑不生效&#xff0c;部分mac也不生效&#xff0c;只有个别的mac生效了&#xff0c;思考了以下几种方面&#xff1a; 1.兼容性问题&#xff1f; 因为是electron项目&#xff0c;不存在浏览器兼容性问题&…

VUE SSR(服务端渲染)

&#x1f916; 作者简介&#xff1a;水煮白菜王&#xff0c;一位前端劝退师 &#x1f47b; &#x1f440; 文章专栏&#xff1a; 前端专栏 &#xff0c;记录一下平时在博客写作中&#xff0c;总结出的一些开发技巧和知识归纳总结✍。 感谢支持&#x1f495;&#x1f495;&#…

ARCGIS国土超级工具集1.5更新说明

ARCGIS国土超级工具集V1.5版本更新说明&#xff1a;因作者近段时间工作比较忙及正在编写ARCGISPro国土超级工具集&#xff08;截图附后&#xff09;的原因&#xff0c;故本次更新为小更新&#xff08;没有增加新功能&#xff0c;只更新了已有的工具&#xff09;。本次更新主要修…

刘鑫炜履新共工新闻社新媒体研究院院长,赋能媒体融合新征程

2025年4月18日&#xff0c;大湾区经济网战略媒体共工新闻社正式对外宣布一项重要人事任命&#xff1a;聘任蚂蚁全媒体总编刘鑫炜为新媒体研究院第一任院长。这一举措&#xff0c;无疑是对刘鑫炜在新媒体领域卓越专业能力与突出行业贡献的又一次高度认可&#xff0c;也预示着共工…

java基础从入门到上手(九):Java - List、Set、Map

一、List集合 List 是一种用于存储有序元素的集合接口&#xff0c;它是 java.util 包中的一部分&#xff0c;并且继承自 Collection 接口。List 接口提供了多种方法&#xff0c;用于按索引操作元素&#xff0c;允许元素重复&#xff0c;并且保持插入顺序。常用的 List 实现类包…

UWP发展历程

通用Windows平台(UWP)发展历程 引言 通用Windows平台(Universal Windows Platform, UWP)是微软为实现"一次编写&#xff0c;处处运行"的愿景而打造的现代应用程序平台。作为微软统一Windows生态系统的核心战略组成部分&#xff0c;UWP代表了从传统Win32应用向现代应…

git忽略已跟踪的文件/指定文件

在项目开发中&#xff0c;有时候我们并不需要git跟踪所有文件&#xff0c;而是需要忽略掉某些指定的文件或文件夹&#xff0c;怎么操作呢&#xff1f;我们分两种情况讨论&#xff1a; 1. 要忽略的文件之前并未被git跟踪 这种情况常用的方法是在项目的根目录下创建和编辑.gitig…

AI 组件库是什么?如何影响UI的开发?

AI组件库是基于人工智能技术构建的、面向用户界面&#xff08;UI&#xff09;开发的预制模块集合。它们结合了传统UI组件&#xff08;如按钮、表单、图表&#xff09;与AI能力&#xff08;如机器学习、自然语言处理、计算机视觉&#xff09;&#xff0c;旨在简化开发流程并增强…

【Win】 cmd 执行curl命令时,输出 ‘命令管道位置 1 的 cmdlet Invoke-WebRequest 请为以下参数提供值: Uri: ’ ?

1.原因&#xff1a; 有一个名为 Invoke-WebRequest 的 CmdLet&#xff0c;其别名为 curl。因此&#xff0c;当您执行此命令时&#xff0c;它会尝试使用 Invoke-WebRequest&#xff0c;而不是使用 curl。 2.解决办法 在cmd中输入如下命令删除这个curl别名&#xff1a; Remov…