[!ABSTRACT] 核心摘要项目编号 :质效精研 · P36专业领域 :医疗质量管理 / 数据分析 / 质管信息化核心问题 :质管办每天面对海量 Excel、CSV、数据库导出文件,手工核查 1 个月的病案首页要 3 天,一个 Python 脚本只要 10 分钟——质管人要不要学代码?三条战线 :
🟢 基础扫盲:Python 在医院质管的现实价值、3 个 80% 问题、Excel → SQL → Python 学习路径、5 大应用清单
🟡 实战进阶:5 个核心库 + 10 个质控实战场景(全部带 Python 代码)+ 质控 Checklist
🔴 极客升维:Jupyter Notebook 协作、Jinja2 自动报表、病历文本 NLP、Streamlit 简易 Web 应用目标篇幅 :9,000-11,000 字
前言:周三下午 4 点,质控员小李的 3 天 vs Python 的 10 分钟 周三下午 4 点,深圳市某三甲医院质管办。
质控员小李对着电脑发呆。桌面上摊着 30 个 Excel——HIS 系统导出的「2026 年 5 月全院病案首页数据」,每个科室 1 个文件,共 12,847 条记录。她需要做的事很明确:
核查主要诊断编码是否为空;
核查主要手术操作是否漏填;
核查入院病情与出院诊断是否符合;
核查 24 小时内归档率;
统计每个科室的入组率、CMI、时间消耗指数;
输出 1 份 30 页的《5 月病案首页质控月报》。
按她过去 3 年的经验,这事要 3 天——一个字段一个字段筛选、复制、粘贴、汇总,中间还要反复核对。
她叹了口气,打开一个新的 Jupyter Notebook,在第一个单元格里敲下:
1 2 3 4 import pandas as pddf = pd.concat([pd.read_excel(f) for f in files], ignore_index=True ) print (df.shape)
10 分钟后,她把月报交给主任。主任看了 3 秒,问了一句:“你今天怎么这么快?”
她说:”我学了一点 Python。 “
这就是 P36 要讲的事——质管人要不要学代码?答案是:要。但不是「成为程序员」,而是「让代码替我干重复活」 。
这一篇,我们讲清楚四件事:
Python 在医院质管的现实价值,以及「3 个 80%」问题;
5 个核心库 + 10 个实战场景(每个场景都带可运行的 Python 代码);
极客层面的协作、自动报表、NLP、Web 应用;
一位三甲医院质控员的真实转型案例,以及 30 天行动清单。
不绕弯子,我们开始。
Part 1:基础扫盲层——质管人要不要学 Python? 很多质管同行听到「Python」「代码」,第一反应是「那是信息科的事」「我是医生不是程序员」「学了也用不上」。
这三种反应都对——但都不完整。
一、Python 在医院质管的现实价值 先看 4 个真实场景,看完你再决定要不要学:
场景 1:批量核查病案首页
人工核查 1 个月病案首页 12,847 条 → 3 天; Python 脚本 10 分钟,准确率 100%(代码不会累)。
场景 2:月度指标趋势图自动生成
人工做 1 张折线图 → 30 分钟(HIS 导出 → Excel 整理 → 选数据 → 调格式); Python 一行代码 → 2 秒:df.plot.line()。
场景 3:DRG 入组结果核查
人工对照 1 个 DRG 分组器的输出 → 半天; Python 脚本批量对照 → 3 分钟。
场景 4:抗菌药物 DDDs(Defined Daily Doses,限定日剂量)计算
人工查 WHO ATC 编码 → 对照 DDD 值 → 求和 → 半天; Python 用 pandas + merge → 5 分钟。
这就是 Python 在医院质管的现实价值——它不是「替代人」,而是「把人从重复劳动里解放出来」 。
一个公式总结:
质管人的时间分配 = 80% 重复劳动 + 20% 真正的「分析 + 决策」 Python 的作用 = 把那 80% 重复劳动压缩到 5%
二、质管人学 Python 的「3 个 80%」问题 我把它总结成「3 个 80%」——这是质管人学 Python 的「必要性证明」:
80% 的工作是重复的
质管办的日常工作里,至少有 80% 是「周期性重复」的:每月 1 次的病案首页核查、每月 1 次的指标月报、每季度 1 次的三级公立医院绩效考核数据填报、每次医保飞检前的数据准备、每次三级评审条款的自评表。
这些工作「流程固定、数据格式固定、输出格式固定」——正是 Python 最擅长干的活 。
80% 的数据格式是规整的
医院的数据看似杂乱,其实 80% 都是规整的结构化数据:HIS 导出的 Excel(每个字段都有固定列名)、病案首页(国家卫健委统一规范的 86 项字段)、DRG 分组器输出(标准 CSV)、不良事件上报系统(标准字段)、临床路径系统(标准字典)。
规整的数据 = Python 的菜 。Python 最怕的是「非结构化」,比如一份手写病程记录扫描件——但这种数据只占质管工作的 20%。
80% 的分析只用到 20% 的语法
Python 有 30+ 关键字、上百个内置函数、上万个第三方库——但质管人 80% 的日常分析,只用 5 个库 + 20% 的语法:
库
用途
质管场景使用频率
pandas
表格处理
每天
openpyxl
Excel 读写
每天
pymysql / sqlalchemy
数据库连接
每周
matplotlib / seaborn
图表
每周
numpy
数值计算
每周
也就是说,质管人不需要「精通 Python」,只需要「会用这 5 个库的 20% 功能」 。
[!INFO] 老炮提醒 质管人学 Python,不是「转行当程序员」,而是「给质管工作装一个外挂 」。你不需要懂 Python 的内存管理、多线程、装饰器——你只需要懂「怎么让 Python 替我读 Excel、出报表、画图」。
三、学习路径:Excel → SQL → Python(阶梯式) 很多质管同行一上来就买《Python 编程:从入门到实践》,啃了 200 页,放弃了——因为书里讲的是「开发一个网站」「写一个小游戏」,跟医院质管完全脱节。
我推荐一条**「阶梯式」学习路径**,每一步都跟质管工作直接挂钩:
第 1 阶:Excel 高手(0-3 个月)
如果你 Excel 还在用「筛选 + 复制粘贴」的阶段,先别碰 Python。先把 Excel 学到「数据透视表 + VLOOKUP + 简单函数」的阶段——这一步解决 50% 的日常工作。
第 2 阶:SQL 入门(3-6 个月)
SQL 是「结构化查询语言」,专门用来「问数据库要数据」。医院 HIS、LIS、EMR(电子病历,Electronic Medical Record)系统背后基本都是 MySQL 或 Oracle 数据库——学会 SQL,你就能「直接问数据库要数据」,不用等信息科导出 Excel。
第 3 阶:Python 入门(6-12 个月)
SQL 学到「能自己取数」之后,再学 Python。Python 的入门只需 3 个核心概念:变量与数据类型 (数字、字符串、列表、字典)、流程控制 (if / for / while)、函数与库 (def / import)。把这 3 个概念学会,就能开始写「自动化脚本」了。
第 4 阶:pandas 实战(12-18 个月)
学会 Python 基础语法后,主攻 pandas——这是质管人 80% 工作会用的库。学完 pandas,你的 Excel 工作量会减少 70%。
第 5 阶:可视化 + 数据库 + 报表自动化(18-24 个月)
最后是 matplotlib / seaborn(画图)、pymysql(读数据库)、Jinja2(自动报表)——这是「极客层」的进阶。
[!TIP] 给质管人的学习节奏建议
不要一次性学完所有语法 ——用啥学啥,边用边学;
每学一个语法,立刻找一个质管场景练手 ;
3 个月不写代码,就忘了 ——保持每周写 1-2 次。
四、质控场景的 Python 应用清单 为了让你对「Python 在医院质管能干啥」有直观印象,我列一份应用清单(后续章节会逐个展开):
应用方向
典型场景
替代的人工工作量
数据清洗
去重、缺失值处理、异常值识别
1 周 → 10 分钟
统计计算
CMI、时间消耗指数、DDDs、入组率
1 天 → 5 分钟
报表自动化
月报、季报、年报、专项报告
1 周 → 1 小时
可视化
趋势图、分布图、对比图、驾驶舱
1 天 → 30 分钟
数据质量核查
病案首页核查、字段完整性、逻辑校验
3 天 → 10 分钟
文本分析
病程记录关键词提取、不良事件分类
1 周 → 30 分钟
数据库直连
直接从 HIS 取数,不用等信息科导出
每次节省 1-2 天
Web 应用
质控员在线核查工具、科室自助查询
自建轻量工具
到这里,你应该明白了:Python 不是「程序员的专利」,而是「质管人的外挂」 。下一步,我们进入「怎么用」——5 个核心库 + 10 个实战场景。
Part 2:实战进阶层——5 个核心库 + 10 个质控场景 这一节,我们把质管人最常用的 5 个 Python 库 + 10 个实战场景,逐个拆给你看。每个场景都配可运行的代码——你复制粘贴就能用。
一、5 个核心库速览 在写代码之前,先把 5 个核心库「装到你的工具箱」里:
1. pandas:表格数据处理(最重要)
pandas 的核心数据结构是 DataFrame(可以理解为「加强版 Excel 表」)。一行代码读 Excel:
1 2 3 4 5 6 7 8 import pandas as pddf = pd.read_excel('5月病案首页.xlsx' ) print (df.head()) print (df.shape) print (df.columns) print (df.dtypes) print (df.describe())
2. numpy:数值计算
numpy 是 pandas 的「底层引擎」,处理矩阵和数值运算:
1 2 3 4 5 import numpy as nparr = np.array([1 , 2 , 3 , 4 , 5 ]) print (arr.mean()) print (arr.std())
3. matplotlib / seaborn:可视化
matplotlib 是 Python 最基础的绘图库,seaborn 是「美化版」:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import matplotlib.pyplot as pltmonths = ['1月' , '2月' , '3月' , '4月' , '5月' , '6月' , '7月' , '8月' , '9月' , '10月' , '11月' , '12月' ] values = [85 , 87 , 86 , 88 , 90 , 89 , 91 , 92 , 93 , 92 , 94 , 95 ] plt.rcParams['font.sans-serif' ] = ['SimHei' ] plt.rcParams['axes.unicode_minus' ] = False plt.figure(figsize=(10 , 5 )) plt.plot(months, values, marker='o' ) plt.title('CMI 月度趋势' ) plt.xlabel('月份' ) plt.ylabel('CMI' ) plt.grid(True ) plt.savefig('cmi_trend.png' , dpi=200 ) plt.show()
4. openpyxl:Excel 读写
openpyxl 主要用来「精细控制 Excel 样式」(合并单元格、设置字体、加颜色):
1 2 3 4 5 6 7 8 9 10 11 12 13 from openpyxl import load_workbookfrom openpyxl.styles import Font, PatternFillwb = load_workbook('月报.xlsx' ) ws = wb.active ws['A1' ].font = Font(bold=True , size=14 ) ws['A1' ].fill = PatternFill(start_color='FFFF00' , end_color='FFFF00' , fill_type='solid' ) wb.save('月报_样式.xlsx' )
5. pymysql / sqlalchemy:数据库连接
pymysql 直连 MySQL,sqlalchemy 是「ORM 版」更通用:
1 2 3 4 5 6 7 8 9 10 11 12 import pymysqlconn = pymysql.connect( host='10.1.2.3' , user='quality_reader' , password='******' , database='his_db' , charset='utf8mb4' ) df = pd.read_sql('SELECT * FROM diagnosis LIMIT 1000' , conn) conn.close()
[!WARNING] 数据库访问安全提示
不要用 root / admin 账号直连生产库 ——申请只读账号;
不要在脚本里写明文密码 ——用环境变量或密钥管理;
不要在脚本里改数据 ——分析脚本只读,不改。
二、10 个实战场景(全部带代码) 下面 10 个场景覆盖质管办 80% 的日常工作。每个场景包含「场景描述 + 完整代码 + 运行说明」。
场景 1:批量读取 HIS 导出的 Excel 场景 :HIS 系统每月导出 30 个科室的病案首页 Excel,每个文件结构相同。需要合并成 1 个总表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import pandas as pdimport globimport osfiles = glob.glob('data/病案首页_2026年5月_*.xlsx' ) print (f'共找到 {len (files)} 个文件' )dfs = [] for f in files: dept_name = os.path.basename(f).replace('病案首页_2026年5月_' , '' ).replace('.xlsx' , '' ) df = pd.read_excel(f) df['科室' ] = dept_name dfs.append(df) df_all = pd.concat(dfs, ignore_index=True ) print (f'合并后总行数:{len (df_all)} ' )df_all.to_excel('output/5月病案首页_全院合并.xlsx' , index=False )
效率 :30 个文件,合并时间 5-10 秒;手工复制粘贴至少 2 小时。
场景 2:数据清洗(去重 / 缺失值 / 异常值) 场景 :合并后的全院数据有重复行、有缺失值、有异常值,需要清洗。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import pandas as pddf = pd.read_excel('output/5月病案首页_全院合并.xlsx' ) print (f'去重前行数:{len (df)} ' )df = df.drop_duplicates(subset=['住院号' ], keep='first' ) print (f'去重后行数:{len (df)} ' )missing_rate = df.isnull().sum () / len (df) * 100 print ('缺失率 > 5% 的列:' )print (missing_rate[missing_rate > 5 ].sort_values(ascending=False ))df = df.dropna(subset=['主要诊断编码' ]) median_age = df['年龄' ].median() df['年龄' ] = df['年龄' ].fillna(median_age) df['婚姻状况' ] = df['婚姻状况' ].fillna('未知' ) abnormal_age = df[(df['年龄' ] < 0 ) | (df['年龄' ] > 150 )] print (f'年龄异常记录:{len (abnormal_age)} 条' )df = df[(df['年龄' ] >= 0 ) & (df['年龄' ] <= 150 )] df = df[(df['住院天数' ] >= 0 ) & (df['住院天数' ] <= 365 )] df = df[df['性别' ].isin(['男' , '女' , '未知' ])] print (f'清洗后行数:{len (df)} ' )
效果 :清洗后数据「干净度」从 80% 提升到 99%。
场景 3:数据合并(多表 JOIN) 场景 :有两张表——「患者信息表」(patient_id, 姓名, 性别, 年龄)、「诊断记录表」(patient_id, 诊断编码, 诊断名称)。需要合并成 1 张表用于分析。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import pandas as pddf_patient = pd.read_excel('data/患者信息.xlsx' ) df_diagnosis = pd.read_excel('data/诊断记录.xlsx' ) df_merged = pd.merge(df_patient, df_diagnosis, on='patient_id' , how='inner' ) df_left = pd.merge(df_patient, df_diagnosis, on='patient_id' , how='left' ) print (f'患者表行数:{len (df_patient)} ' )print (f'诊断表行数:{len (df_diagnosis)} ' )print (f'内连接后:{len (df_merged)} ' )
SQL 对照 :SELECT * FROM patient p INNER JOIN diagnosis d ON p.patient_id = d.patient_id;
场景 4:病案首页关键字段核查 场景 :病案首页 86 项字段中,有 15 项是「必填且非空」的。需要自动核查,生成问题清单。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import pandas as pddf = pd.read_excel('output/5月病案首页_全院合并.xlsx' ) required_fields = [ '住院号' , '姓名' , '性别' , '年龄' , '入院日期' , '出院日期' , '主要诊断编码' , '主要诊断名称' , '主要手术操作编码' , '主要手术操作名称' , '入院病情' , '出院病情' , '科别' , '床位医师' ] issues = [] for field in required_fields: if field not in df.columns: print (f'警告:字段「{field} 」不存在' ) continue missing_count = df[field].isnull().sum () empty_count = (df[field].astype(str ).str .strip() == '' ).sum () total_problems = missing_count + empty_count issues.append({ '字段' : field, '缺失数' : missing_count, '空白数' : empty_count, '总问题数' : total_problems, '问题率(%)' : round (total_problems / len (df) * 100 , 2 ) }) df_issues = pd.DataFrame(issues).sort_values('总问题数' , ascending=False ) print (df_issues)df_issues.to_excel('output/病案首页必填字段核查报告.xlsx' , index=False )
输出 :
1 2 3 4 字段 缺失数 空白数 总问题数 问题率(%) 主要手术操作名称 1245 89 1334 10.38 主要手术操作编码 1203 89 1292 10.06 入院病情 56 0 56 0.44
场景 5:不良事件分类统计 场景 :护理部上报的不良事件数据,需要按「级别 + 类别 + 科室」三维统计。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import pandas as pddf = pd.read_excel('data/2026年不良事件.xlsx' ) pivot1 = df.pivot_table( index='事件级别' , columns='事件类别' , values='事件ID' , aggfunc='count' , fill_value=0 , margins=True , margins_name='合计' ) print ('事件级别 × 事件类别:' )print (pivot1)dept_stats = df.groupby('科室' ).agg( 事件总数=('事件ID' , 'count' ), 严重事件数=('事件级别' , lambda x: (x == '严重' ).sum ()), 已结案数=('状态' , lambda x: (x == '已结案' ).sum ()) ).sort_values('事件总数' , ascending=False ) print ('科室统计:' )print (dept_stats)with pd.ExcelWriter('output/不良事件统计月报.xlsx' , engine='openpyxl' ) as writer: pivot1.to_excel(writer, sheet_name='级别×类别' ) dept_stats.to_excel(writer, sheet_name='科室统计' )
场景 6:抗菌药物 DDDs 自动计算 场景 :药剂科要求每月统计抗菌药物 DDDs(DDDs = 总用药量 / DDD 值),衡量抗菌药物使用强度。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import pandas as pddf_use = pd.read_excel('data/5月抗菌药物使用记录.xlsx' ) df_ddd = pd.read_excel('data/抗菌药物DDD字典.xlsx' ) df_merged = pd.merge(df_use, df_ddd, on='药物编码' , how='left' ) df_merged['DDDs' ] = df_merged['用药总量(克)' ] / df_merged['DDD值(克)' ] drug_ddds = df_merged.groupby(['药物名称' , 'ATC分类' ]).agg( 用药总量=('用药总量(克)' , 'sum' ), DDDs=('DDDs' , 'sum' ) ).sort_values('DDDs' , ascending=False ) print (drug_ddds.head(20 ))df_dept = df_merged.groupby('科室' ).agg( DDDs合计=('DDDs' , 'sum' ), 住院人天=('住院人天' , 'sum' ) ) df_dept['DDDs_100人天' ] = df_dept['DDDs合计' ] / df_dept['住院人天' ] * 100 print ('科室抗菌药物使用强度:' )print (df_dept.sort_values('DDDs_100人天' , ascending=False ))
[!INFO] 关于 DDDs DDDs(DDDs,Defined Daily Doses,限定日剂量数)反映的是「每种药物被使用的平均日剂量数」,数值越大,说明该药使用越广泛。WHO ATC/DDD 系统是国际通用的药物计量标准。
场景 7:临床路径入径率分析 场景 :统计每个科室每个月的「临床路径入径率」「完成率」「变异率」。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import pandas as pddf = pd.read_excel('data/临床路径数据_2026.xlsx' ) grouped = df.groupby(['科室' , '月份' , '路径名称' ]).agg( 符合路径=('是否符合' , lambda x: (x == '是' ).sum ()), 实际入径=('是否入径' , lambda x: (x == '是' ).sum ()), 完成路径=('是否完成' , lambda x: (x == '是' ).sum ()), 发生变异=('是否变异' , lambda x: (x == '是' ).sum ()) ) grouped['入径率' ] = grouped['实际入径' ] / grouped['符合路径' ] * 100 grouped['完成率' ] = grouped['完成路径' ] / grouped['实际入径' ] * 100 grouped['变异率' ] = grouped['发生变异' ] / grouped['实际入径' ] * 100 grouped = grouped.round (2 ) high_variation = grouped[grouped['变异率' ] > 30 ].sort_values('变异率' , ascending=False ) print ('高变异率路径:' )print (high_variation)grouped.to_excel('output/临床路径入径率分析.xlsx' )
场景 8:DRG 入组结果核查 场景 :DRG 分组器输出的入组结果,需要核查「入组率」「低风险死亡率」「错误入组」。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 import pandas as pddf = pd.read_excel('data/5月DRG入组结果.xlsx' ) total_rate = (df['DRG编码' ].notnull().sum () / len (df)) * 100 print (f'全院 DRG 入组率:{total_rate:.2 f} %' )dept_rate = df.groupby('科室' ).apply( lambda x: pd.Series({ '病例数' : len (x), '入组数' : x['DRG编码' ].notnull().sum (), '入组率(%)' : round (x['DRG编码' ].notnull().sum () / len (x) * 100 , 2 ) }) ).sort_values('入组率(%)' , ascending=False ) warning = dept_rate[dept_rate['入组率(%)' ] < 95 ] print ('入组率 < 95% 的科室:' )print (warning)total_weight = df['DRG权重' ].sum () cni_count = len (df[df['DRG编码' ].notnull()]) cmi = total_weight / cni_count print (f'全院 CMI:{cmi:.4 f} ' )dept_rate.to_excel('output/DRG入组率核查.xlsx' )
场景 9:指标月度趋势图自动生成 场景 :每月输出 5-10 个关键指标的「趋势图」,用于月报。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 import pandas as pdimport matplotlib.pyplot as pltimport osplt.rcParams['font.sans-serif' ] = ['SimHei' ] plt.rcParams['axes.unicode_minus' ] = False df = pd.read_excel('data/2025年指标数据.xlsx' ) os.makedirs('output/趋势图' , exist_ok=True ) indicators = ['CMI' , '入组率' , '平均住院日' , '抗菌药物使用强度' , '手术并发症发生率' ] fig, axes = plt.subplots(2 , 3 , figsize=(15 , 10 )) axes = axes.flatten() for i, ind in enumerate (indicators): if ind not in df.columns: continue ax = axes[i] ax.plot(df['月份' ], df[ind], marker='o' , linewidth=2 ) ax.set_title(ind, fontsize=14 ) ax.set_xlabel('月份' ) ax.set_ylabel(ind) ax.grid(True , alpha=0.3 ) ax.tick_params(axis='x' , rotation=45 ) for j in range (len (indicators), len (axes)): axes[j].set_visible(False ) plt.tight_layout() plt.savefig('output/趋势图/月度指标趋势图.png' , dpi=200 , bbox_inches='tight' ) plt.show() print ('趋势图已生成' )
场景 10:数据质量自动报告 场景 :每月自动出一份《数据质量报告》,包括「完整性、一致性、及时性、唯一性」四个维度。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 import pandas as pdfrom datetime import datetimedf = pd.read_excel('output/5月病案首页_全院合并.xlsx' ) report = [] report.append(f'数据质量报告 - {datetime.now().strftime("%Y-%m-%d" )} ' ) report.append(f'总记录数:{len (df)} ' ) report.append('=' * 50 ) report.append('\n【维度 1:完整性】' ) required_fields = ['主要诊断编码' , '主要手术操作编码' , '入院病情' , '出院病情' ] for field in required_fields: if field in df.columns: missing_rate = df[field].isnull().sum () / len (df) * 100 status = '通过' if missing_rate < 1 else '不通过' report.append(f' {field} :缺失率 {missing_rate:.2 f} % [{status} ]' ) report.append('\n【维度 2:一致性】' ) invalid_date = (df['入院日期' ] >= df['出院日期' ]).sum () report.append(f' 入院日期 >= 出院日期:{invalid_date} 条' ) icd_pattern = df['主要诊断编码' ].astype(str ).str .match (r'^[A-Z]\d{2}(\.\d{1,2})?$' ) invalid_icd = (~icd_pattern & df['主要诊断编码' ].notnull()).sum () report.append(f' 主要诊断编码格式不规范:{invalid_icd} 条' ) report.append('\n【维度 3:及时性】' ) df['归档时效' ] = (df['归档日期' ] - df['出院日期' ]).dt.total_seconds() / 3600 on_time_rate = (df['归档时效' ] <= 24 ).sum () / len (df) * 100 report.append(f' 24 小时内归档率:{on_time_rate:.2 f} %' ) report.append('\n【维度 4:唯一性】' ) duplicate_id = df.duplicated(subset=['住院号' ], keep=False ).sum () report.append(f' 住院号重复:{duplicate_id} 条' ) with open ('output/数据质量报告_5月.txt' , 'w' , encoding='utf-8' ) as f: f.write('\n' .join(report)) print ('\n' .join(report))
输出示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 数据质量报告 - 2026-06-24 总记录数:12847 ================================================== 【维度 1:完整性】 主要诊断编码:缺失率 0.12% [通过] 主要手术操作编码:缺失率 10.06% [不通过] 【维度 2:一致性】 入院日期 >= 出院日期:3 条 主要诊断编码格式不规范:127 条 【维度 3:及时性】 24 小时内归档率:89.32% 【维度 4:唯一性】 住院号重复:0 条
三、质控 Checklist:10 项核查点 Python 脚本写完后,怎么知道脚本「靠不靠谱」?用这张 Checklist:
序号
核查项
检查方法
通过标准
1
脚本运行成功率
连续 3 个月运行同一脚本
≥ 99%
2
数据准确率
与人工核查 100 条样本对比
≥ 99%
3
效率提升比
对比脚本运行时长 vs 人工时长
≥ 10 倍
4
字段口径一致性
与指标库定义文档比对
100% 一致
5
空值 / 异常值处理
故意构造 100 条异常数据测试
全部按预期处理
6
版本控制
脚本用 git 管理,变更可追溯
所有变更在 git log
7
文档完整性
每个脚本有 README,说明输入 / 输出 / 依赖
100% 覆盖
8
权限最小化
数据库账号只有读权限
验证账号权限
9
可重复运行
同一脚本运行两次结果一致
完全一致
10
维护成本
每季度人工维护时长
≤ 4 小时/季度
[!TIP] 落地建议 把这张 Checklist 嵌入 CI/CD(持续集成/持续部署)流水线,每次脚本变更前自动跑一遍——脚本质量有保障,才不会「跑 1 次准,跑 100 次偏」。
到这里,10 个实战场景 + 5 个核心库都拆完了。但这只是「会用 Python」的阶段——下一步,我们看「把 Python 用到极致」的极客层面。
Part 3:极客升维层——从「脚本」到「系统」 上一节的脚本,适合个人使用;这一节的工具,适合团队协作 + 流程自动化。
一、Jupyter Notebook:质管团队的协作神器 Jupyter Notebook 是一种「交互式编程环境」——你可以一段一段地写代码,每一段的结果(表格、图表、文字)直接显示在代码下面。
为什么质管团队特别适合用 Jupyter?
传统脚本
Jupyter Notebook
一次跑完,中间看不到结果
一段段执行,每段有输出
文字说明要写在另一个文档
文字 + 代码 + 图表混排
团队协作靠 git diff
直接看「输出」就知道改了什么
出问题要从头跑
可以只跑出问题的部分
质管团队用 Jupyter 的 3 个真实场景 :
月报协作 :质管办 3 个人分工写 3 个 Cell,合并成 1 个月报 Notebook;
培训教学 :信息科给临床讲解数据时,用 Jupyter 边讲边演示;
复盘分析 :事故复盘时,用 Jupyter 一步步追溯数据,留作「事故档案」。
二、Python 自动化报表(Jinja2 + PDF) 场景 :每月要出 1 份《全院质控月报》(PDF),内容固定,只是数据变。
方案 :用 Jinja2(模板引擎)+ WeasyPrint(PDF 生成器)——把「文字模板 + 数据」自动合并成 PDF。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 from jinja2 import Templateimport pandas as pdfrom datetime import datetimedf = pd.read_excel('output/5月病案首页_全院合并.xlsx' ) total = len (df) grouped_rate = df['DRG编码' ].notnull().sum () / total * 100 cmi = df['DRG权重' ].sum () / df['DRG编码' ].notnull().sum () data = { 'report_month' : '2026年5月' , 'generate_date' : datetime.now().strftime('%Y-%m-%d' ), 'total_cases' : total, 'drg_rate' : f'{grouped_rate:.2 f} ' , 'cmi' : f'{cmi:.4 f} ' , 'avg_los' : f'{df["住院天数" ].mean():.2 f} ' } template_str = """ <!DOCTYPE html> <html> <head><meta charset="utf-8"><title>质控月报</title></head> <body> <h1>{{ report_month }} 全院质控月报</h1> <p>生成日期:{{ generate_date }}</p> <h2>一、总体情况</h2> <ul> <li>出院病例总数:<b>{{ total_cases }}</b> 例</li> <li>DRG 入组率:<b>{{ drg_rate }}%</b></li> <li>CMI:<b>{{ cmi }}</b></li> <li>平均住院日:<b>{{ avg_los }}</b> 天</li> </ul> </body> </html> """ template = Template(template_str) html_content = template.render(**data) with open ('output/月报.html' , 'w' , encoding='utf-8' ) as f: f.write(html_content)
效果 :改模板,数据自动填入;每月只需跑 1 次脚本,PDF 月报自动生成。
三、病历文本 NLP(关键词提取) 场景 :病程记录、出院小结是「非结构化文本」,如何自动提取关键信息?
方案 :用 jieba(中文分词)+ re(正则表达式)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 import jiebaimport resample_text = """ 患者于 2026-05-10 在全身麻醉下行腹腔镜下胆囊切除术, 术中出血约 50ml,术后安返病房。术后第 2 天出现发热, 体温最高 38.5℃,考虑切口感染,给予头孢呋辛钠抗感染治疗后好转。 """ words = jieba.lcut(sample_text) print ('分词结果:' )print ('/' .join(words))surgery_match = re.search(r'行(.*?术)[,。]' , sample_text) if surgery_match: print (f'手术名称:{surgery_match.group(1 )} ' ) dates = re.findall(r'\d{4}-\d{2}-\d{2}' , sample_text) print (f'涉及日期:{dates} ' )temps = re.findall(r'(\d+\.?\d*)℃' , sample_text) print (f'体温记录:{temps} ' )complication_keywords = ['感染' , '出血' , '发热' , '疼痛' , '肿胀' , '渗出' ] found = [k for k in complication_keywords if k in sample_text] print (f'并发症关键词:{found} ' )
输出 :
1 2 3 4 手术名称:腹腔镜下胆囊切除术 涉及日期:['2026-05-10'] 体温记录:['38.5'] 并发症关键词:['感染', '发热']
进阶 :用 sklearn 的 TF-IDF 或 BERT 模型做「病历自动分类」(病种、病情严重程度)——这一层需要更多 NLP 基础,可以放到 P37 详述。
四、Streamlit:5 分钟做一个 Web 应用 场景 :质管办做了一个「病案首页核查工具」脚本,但临床科室不会用 Python——怎么让临床也能用?
方案 :用 Streamlit 把 Python 脚本包装成 Web 应用,临床打开浏览器就能用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import streamlit as stimport pandas as pdst.title('病案首页核查工具' ) uploaded = st.file_uploader('上传病案首页 Excel' , type =['xlsx' ]) if uploaded: df = pd.read_excel(uploaded) st.success(f'共读取 {len (df)} 条记录' ) st.subheader('必填字段核查' ) required = ['主要诊断编码' , '主要手术操作编码' , '入院病情' ] for field in required: if field in df.columns: missing = df[field].isnull().sum () rate = missing / len (df) * 100 if rate > 5 : st.error(f'{field} :缺失 {missing} 条 ({rate:.2 f} %) - 不通过' ) else : st.success(f'{field} :缺失 {missing} 条 ({rate:.2 f} %) - 通过' ) if st.checkbox('显示原始数据' ): st.dataframe(df.head(100 ))
运行 :streamlit run streamlit_app.py,打开浏览器访问 http://localhost:8501,临床就能直接上传 Excel 看核查结果——完全不用懂 Python 。
五、整体架构(Mermaid 图) 为了让你看清「Python 自动化体系」的全貌,画一张架构图:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 graph TB subgraph Data["数据源层"] D1[HIS 系统] D2[LIS 检验系统] D3[PACS 影像系统] D4[EMR 电子病历] D5[不良事件系统] D6[DRG 分组器] end subgraph ETL["ETL 层"] E1[Python 脚本读取] E2[数据清洗] E3[数据合并] E4[数据校验] end subgraph Analysis["分析层"] A1[统计分析] A2[指标计算] A3[趋势预测] A4[异常检测] end subgraph Output["输出层"] O1[Excel 月报] O2[PDF 自动报表] O3[图表可视化] O4[Streamlit Web 工具] end subgraph User["用户层"] U1[质管办] U2[临床科室] U3[职能部门] U4[院长] end Data --> ETL --> Analysis --> Output --> User
六、工作流流程图(Mermaid) 再画一张「质控员日常 Python 工作流」:
1 2 3 4 5 6 7 8 9 10 11 12 flowchart LR A[HIS 导出 Excel] --> B[Python 脚本读取] B --> C{数据完整?} C -->|否| D[数据清洗] C -->|是| E[分析计算] D --> E E --> F[生成图表] E --> G[生成月报] F --> H[月报整合] G --> H H --> I[质管办主任审核] I --> J[提交院领导]
到这里,极客层面的工具都摆齐了。但这一切要落地,中间还隔着「人」这道坎——下一节,我们走进一家三甲医院的真实场景,看一个质控员是怎么从「手工」走到「自动化」的。
Part 4:真实案例——某三甲医院质控员的 Python 转型之路 2025 年,深圳某三甲医院(化名「海珠医院」,开放床位 1800 张,日均门诊 9000 人次)质管办来了一位新人——小陈,护理学硕士,刚毕业 1 年。
一、起点:3 天 vs 10 分钟 小陈入职第 1 周 :
主任交代:「把 2025 年 1 月的病案首页核查报告做出来」;
数据:1 个 Excel,8,234 条;
工作内容:核查 15 个必填字段、统计 30 个科室的入组率、生成 1 份月报;
用时:3 天 (筛选、复制、粘贴、汇总、出图表、写报告)。
小陈入职第 3 个月 :
同样的工作,她用 Python 脚本完成;
用时:10 分钟 (脚本 1 次运行,自动出报表、自动出图、自动生成月报)。
效率提升:432 倍 。
二、转型路径:6 个月从「零基础」到「自动化」
月份
学习内容
实际产出
第 1 月
Excel 高阶功能 + SQL 基础
把 HIS 导出的 Excel 用 SQL 直连数据库,节省每天 2 小时「等导出」
第 2 月
Python 基础语法 + pandas 入门
写出第 1 个脚本:批量核查必填字段
第 3 月
pandas 进阶 + matplotlib 绘图
月报图表自动化,从「手工画图」变「脚本出图」
第 4 月
openpyxl + Jinja2 报表模板
月报自动生成,从「手工排版」变「模板填充」
第 5 月
pymysql + 数据库直连
直连 HIS 数据库,不用等信息科导出
第 6 月
Streamlit + 团队协作
给临床做了一个「病案首页在线核查」Web 工具
三、改革效果(6 个月后)
维度
改革前
改革后
变化
月报出稿时间
3 天
1 小时
-92%
数据准确率
95%(手工有错)
99.5%(代码不累)
+4.5 pp
临床「等数据」时长
每周 4 小时
每周 0.5 小时
-87.5%
质管办可分析维度
5-8 个
20+ 个
+150%
四、三条经验
[!EXAMPLE] 小陈的转型经验
从「最痛的一个点」切入 :小陈第 1 个脚本不是「全院自动化」,而是「必填字段核查」——就这一件事,让她每天节省 1 小时,从此有了「继续学」的动力。
每学一个语法,立刻找一个质管场景练手 :她学 merge 的那天,就找了「患者表 + 诊断表合并」这个真实场景;学 groupby 的那天,就找了「按科室统计入组率」。学以致用,3 个月就出师 。
把自己变成「团队的桥梁」 :小陈学会 Python 后,主动帮信息科写脚本、帮临床做核查工具——她从「新人」变成了「质管办最被需要的人」。技能,是医院里最硬的「关系」 。
到这里,4 个层级都拆完了。最后,我们给出 30 天行动清单 + P37 预告。
结语:Python 不是「程序员的专利」,是「质管人的外挂」 回到周三下午 4 点的小李。
她面前的那 30 个 Excel 不会消失——病案首页每个月都要核查,月报每个月都要出,指标每个月都要统计。但从今天起,她做三件事:
第一,装上 Python 环境 ——Anaconda 一键安装,30 分钟搞定。
第二,写第 1 个脚本 ——哪怕只是「读 1 个 Excel,看前 5 行」——只要迈出第一步,后面就顺了。
第三,加入 1 个 Python 质管社群 ——遇到问题有人问、有人答,比自己摸索快 10 倍。
她不需要成为程序员,她只需要让 Python 替她干那 80% 的重复活 。
全文三句话
[!SUCCESS] 一句话总结
质管人学 Python 不是「转行」,是「给质管工作装外挂」——3 个 80% 问题决定了学 Python 是「性价比最高的技能投资」 。
5 个核心库 + 10 个实战场景覆盖质管办 80% 的工作——pandas 读表、numpy 算数值、matplotlib 出图、openpyxl 控 Excel、pymysql 连数据库,这 5 个就够用 。
从「脚本」到「系统」要走 3 步:Jupyter Notebook 协作、Jinja2 + PDF 自动报表、Streamlit 做 Web 工具——每一步都让 Python 从「个人技能」升级为「团队能力」 。
30 天行动清单:从「零基础」到「会写脚本」
[!TIP] 给质管人的「30 天 Python 入门清单」
天数
动作
输出物
Day 1
安装 Anaconda,打开 Jupyter Notebook
环境就绪
Day 2
第 1 个脚本:读 1 个 Excel,看前 5 行
df.head() 运行成功
Day 3
学 pandas 的 describe() / info() / shape
3 行代码搞定
Day 4
学 dropna() / drop_duplicates()
清洗 1 个真实 Excel
Day 5
学 groupby() + agg()
按科室统计 1 个指标
Day 6
实战 1:批量合并 30 个科室的病案首页
合并后的总表
Day 7
实战 2:数据清洗(去重 + 缺失值 + 异常值)
清洗后的总表
Day 8
实战 3:病案首页必填字段核查
核查报告 Excel
Day 9
学 matplotlib 的 plot() + figure()
1 张折线图
Day 10
实战 4:指标月度趋势图自动生成
5 张趋势图 PNG
Day 11
学 openpyxl 的 Font + PatternFill
1 份带样式的 Excel
Day 12
学 pivot_table()
1 张透视表
Day 13
实战 5:不良事件分类统计
透视表 + 科室统计
Day 14
学 merge()
合并 2 张表
Day 15
学 numpy 的 mean() / std() / median()
3 个统计函数
Day 16
实战 6:抗菌药物 DDDs 自动计算
科室 DDDs 报表
Day 17
实战 7:临床路径入径率分析
路径入径率报表
Day 18
实战 8:DRG 入组结果核查
入组率 + CMI + 时间消耗指数
Day 19
实战 9:数据质量自动报告
4 维度数据质量报告
Day 20
学 pymysql 直连 MySQL
1 个 SQL 查询结果
Day 21
实战 10:从 HIS 数据库直接取数
不再等信息科导出
Day 22
学 Jinja2 模板语法
1 个 HTML 模板
Day 23
实战:用 Jinja2 生成月报 HTML
1 份自动月报
Day 24
学 Streamlit 基础
1 个简单 Web 应用
Day 25
实战:把核查脚本包装成 Streamlit
临床可用的 Web 工具
Day 26
学 jieba 中文分词 + re 正则
病程记录分词结果
Day 27
实战:病历文本关键词提取
手术名 + 并发症关键词
Day 28
把所有脚本用 git 管理
GitHub 仓库
Day 29
写一份《我的 Python 学习笔记》
学习笔记 Markdown
Day 30
30 天复盘:出《P36 30 天落地报告》
复盘报告 + 下一阶段计划
30 天不是空话,是从「不会 Python」到「会写脚本」的硬约束。 Day 1 必须今天完成,Day 30 必须 30 天后能跑出 1 份自动化月报——这就是质管人学 Python 该有的节奏。
[!INFO] 系列预告
P37 AI 辅助质控 :大语言模型 + 病历质控——AI 能不能帮质控员自动核查病案首页、自动识别疑似医疗不良事件?
P38 数据治理实战 :从「脏数据」到「干净数据」——医院数据治理的 6 步法
P39 质管信息化选型 :选 HIS、选 BI、选 AI——质管办的信息化该怎么「搭」?
关注「质领未来」,每一篇,都让质管人少走一年弯路。 留言区留下你 学 Python 踩过最深的坑 (比如装环境装到崩溃、写脚本写到半夜、出错找不到原因、坚持不下去想放弃……),狼叔会在 P37-P39 里挑 3 个高频痛点做深度拆解。
《质效精研》P36 · Python 赋能:质管人也要学一点代码,批量处理病历数据 深圳市盐田区人民医院质管办 · 2026-06-24