处方点评(prescription-review)
工作流程
- 解析:用
scripts/parse_prescriptions.py的load_prescriptions(path, sheet_name, header=1)读入处方Excel。平台导出格式为:第1行标题、第2行列名(序号/处方日期/年龄/诊断/处方用药情况/点评意见),"处方用药情况"为多行文本(序号 药品名 规格 用法 频次 单次剂量 总量 金额元)。解析失败行保留原文,按R0交人工核对。 - 分组+初筛:运行
python3 scripts/batch_review.py 处方.xlsx -o 结果.xlsx [--sheet 表名],输出带六类分组标记列、"疑似问题"列的Excel;汇总打印各专项处方数与处方率、门诊抗菌药物使用率;若导出含科室列,自动生成"科室分布"sheet(计数+占比)。 - 复核:逐条复核"疑似问题"命中的处方。规则口径见下文【分组口径与初筛规则】。初筛只标疑点,不得把规则命中直接写成不合理结论——须结合诊断、说明书与指南人工确认。
- 写存在问题:确认的不合理处方按规范类型归类(遴选药物不适宜/用法用量不适宜/联合用药不适宜等),每类对照下文【典型不合理处方情形清单】写成叙述式案例:处方概要→问题→指南/说明书依据→可执行建议。
- 生成小结:按下文【月度小结结构】生成,四段式:一、总体情况(点评依据+不合理处方数与比率+主要问题类型+科室分布表);二、专项情况(六类专项处方数与处方率+专项不适宜表);三、不合理处方存在问题(分类型叙述,详细见附件);四、总结(问题概括+对医师的要求)。落款:制表人、医院名称、处方点评小组、日期。
指标口径
- 门诊只报门诊抗菌药物使用率(=含全身用抗菌药物处方数/点评处方总数,二级医院目标≤20%),不计算DDDs与使用强度。口径细节见下文【门诊抗菌药物使用率计算口径】。
- 糖皮质激素专项只计全身用制剂;麻精专项严格按国家目录=麻醉药品+第一类精神药品(丙泊酚、右美托咪定等舒适化麻醉用药非国家目录品种,不计入);精二与含特殊药品复方制剂只作监控预警、不计入专项数。依据与调整方法见下文【分组口径与初筛规则】。
分组清单维护
scripts/group_lists.json 是六类专项的药品识别库,按本院在用药品维护:新药入库时在对应数组追加关键词或品名;与平台计数出现个位数差异时先核对品种口径再调整。
月度小结结构
按四段式生成,落款为制表人、医院名称、处方点评小组、日期:
- 总体情况:抽查张数与来源(智慧药学平台随机抽取门急诊处方)、点评依据(《处方管理办法》《2015抗菌药物临床应用指导原则》《中华人民共和国药典临床用药须知》等)、不合理处方数与比率、主要问题类型,附科室分布表(处方科室名称/计数/占比)。
- 专项情况:六类专项处方数与处方率,附专项表(专项名称/专项处方数/不适宜处方数/不适宜率),麻精专项列名"麻、精一处方"。
- 不合理处方存在问题(详细见附件):按规范类型分节(1.遴选药物不适宜 2.用法用量不适宜 3.联合用药不适宜……),每类叙述式书写:抽查发现患者诊断为××,处方使用××,根据《××》××条款……建议××。
- 总结:问题概括+对医师的要求(对精神药品、抗菌药物、PPI类药物、中成药等重点监控药品严格按文件要求,明确诊断、核对适应症与用法用量)。
其他处方导出格式
列名或行格式不同时:调整 header 参数或用药文本正则(parse_prescriptions.py 顶部模式常量);无法解析的行不会丢失,会保留原文进入R0复核队列。
附录A:分组口径与初筛规则
一、六类专项分组口径
每张处方可同时属于多个专项,按其所含药品判定。专项统计口径与智慧药学平台保持一致:
| 专项 | 判定口径 | 点评关注重点 |
|---|---|---|
| 基本药物 | 药品通用名在国家基本药物目录内(优先用HIS/平台基药标识列,其次用 group_lists.json 关键词) | 基药处方率、优先选择是否合理 |
| 抗菌药物 | 全身用抗菌药物(含抗真菌药);滴眼/滴耳/外用软膏/阴道栓等局部制剂及抗病毒药不计入 | 有无指征、品种选择、用法用量、分级管理权限 |
| 中成药 | 国药准字Z品种(含民族药、含化药成分中成药如维C银翘片),按 group_lists.json 品种清单精确匹配 | 辨证用药、功能主治与诊断相符、联用重叠、含化药成分重复 |
| 糖皮质激素 | 仅全身用(口服/注射/吸入雾化);乳膏、软膏、眼膏、滴眼液、鼻喷雾剂等局部制剂不计入专项处方数 | 指征、疗程、退热等不规范使用 |
| 质子泵抑制剂 | PPI及P-CAB(伏诺拉生、替戈拉生) | 无指征用药、超常规频次(如艾司奥美拉唑Bid用于慢性胃炎)、预防用药合理性 |
| 麻、精一药品 | 严格按国家最新版《麻醉药品品种目录》《精神药品品种目录》:麻醉药品+第一类精神药品。丙泊酚、右美托咪定等舒适化麻醉用药非国家目录品种,不计入;精二及含特殊药品复方制剂不计入专项数,仅作规则监控预警 | 处方权限、剂量与给药时长、用量合理性 |
分组清单维护:scripts/group_lists.json 按本院在用药品维护,新药入库时追加,
无需修改代码。与平台计数出现个位数差异时,先核对品种口径再调整清单。
二、规则引擎初筛规则(R0–R9)
初筛只标疑点,不直接下结论。命中规则的处方必须由点评药师复核后方可写入小结。
| 编号 | 规则 | 依据要点 |
|---|---|---|
| R0 | 药品行解析失败 | HIS导出格式异常,人工核对用法用量 |
| R1 | 单张处方药品>5种 | 《处方管理办法》第六条:每张处方不得超过5种药品 |
| R2 | 抗菌药物诊断中无感染相关描述 | 《抗菌药物临床应用指导原则》无指征用药 |
| R3 | 儿童禁忌用药 | 尼美舒利<12岁禁用;全身用氟喹诺酮<18岁不推荐;四环素类<8岁禁用 |
| R4 | 同类药品≥2种(NSAIDs/抗组胺/他汀/ARB/复方感冒药/胰岛素促泌剂);中成药≥3种联用 | 重复用药、功效重叠;促泌剂联用见《中国糖尿病防治指南》 |
| R5 | 全身用糖皮质激素诊断无常见适应证描述 | 激素用于普通上感退热等属典型不合理 |
| R6 | PPI/P-CAB诊断无酸相关疾病描述 | 无指征用药;另核查频次(常规剂量每日1次) |
| R7 | 精二药品估算用量>7天;麻醉药品用量偏大 | 《处方管理办法》第23–24条处方限量 |
| R8 | 诊断缺失或仅为"开药" | 处方书写规范 |
| R9 | 中药注射剂使用 | 重点监控品种,核查适应证与溶媒 |
三、点评意见书写规范
- 不合理类型用规范术语:遴选(遴选药物)不适宜、用法用量不适宜、联合用药不适宜、重复给药、有配伍禁忌或不良相互作用、无正当理由超说明书用药、处方书写不规范。
- 附依据:写明文件名称+关键内容,如《中成药临床应用指导原则》《质子泵抑制剂优化应用专家共识》《中国糖尿病防治指南(2024版)》、药品说明书;不写"根据相关规定"这类空话。
- 可执行:给出替代或调整建议(品种、剂量、频次、疗程),如"针对胃肠炎的腹痛腹泻建议辨证考虑腹可安片或保济丸"。
- 跨机构或上期已归类问题需注明历史处理情况,要求补充证明材料。
附录B:典型不合理处方情形清单
按月点评时对照本清单提取典型案例,每类至少保留1份实例,全院通报通常选20份以上、
覆盖不同科室与不同分组。编号与初筛规则(见 review-rules.md)对应可互相印证。
抗菌药物类
- 无感染诊断使用抗菌药物(如"头痛""体检"开头孢)
- 上呼吸道感染(病毒性)常规联用两种抗菌药物
- 抗菌药物给药频次错误(如头孢克洛 Qd 应为 Tid,时间依赖型未按半衰期给药)
- 氟喹诺酮用于18岁以下、尼美舒利用于12岁以下
- 围手术期/拔牙后预防用药疗程过长(>48小时无依据延长)
- 甲硝唑单用于需氧菌感染,品种选择错误
- 抗菌药物超分级管理权限开具(特殊使用级门诊使用)
中成药类
- 中成药功能主治与诊断不符(如风寒感冒用清开灵等寒凉药)
- 功效相近中成药≥3种联用(重复用药)
- 含化药成分中成药与单方化药重复(维C银翘片+对乙酰氨基酚;咳特灵+氯苯那敏)
- 中药注射剂超适应证、溶媒选择不当、与抗菌药物同瓶混合
糖皮质激素类
- 地塞米松/甲泼尼龙用于普通感冒、发热退热
- 全身用激素无过敏/哮喘/自身免疫等适应证描述
- 激素长疗程无减量方案
PPI类
- PPI无酸相关疾病诊断(如为"护胃"常规搭车开具)
- 注射用PPI用于可口服患者
- PPI与H2受体拮抗剂/铋剂无指征联用
麻精及重点监控药品类
- 第二类精神药品单张处方超过7日常用量
- 含可待因/麻黄碱复方制剂用于儿童、或与其他含相同成分药品联用
- 麻醉药品、精一药品处方权或限量不符
通用书写与用法类
- 单张处方超过5种药品
- 诊断缺失、以"开药"代替诊断
- 给药途径与剂型不符(如外用制剂写口服)
- 单次剂量超过说明书极量
- 用药天数与总量不符(如 Bid×7天却只开4粒)
案例书写模板
> 处方概要:X岁男/女,诊断XX;用药XX。
> 问题:不合理类型(用规范术语)。
> 依据:指南/说明书具体条款。
> 建议:可直接执行的调整方案。
附录C:门诊抗菌药物使用率计算口径
门诊点评只上报门诊抗菌药物使用率,不计算DDDs与使用强度(AUD属住院指标,门诊无处方人天数数据,不得硬算)。
一、公式
门诊抗菌药物使用率 = 含全身用抗菌药物处方数 / 同期点评处方总数 × 100%
scripts/batch_review.py 汇总输出时自动计算并打印该指标。
二、计入与不计入
- 计入:全身用(口服/注射/输注)抗菌药物,含抗真菌药(氟康唑、伊曲康唑、特比萘芬口服等)。
- 不计入:滴眼液、滴耳液、外用软膏/乳膏/凝胶、阴道栓、洗剂等局部制剂;抗病毒药(奥司他韦、恩替卡韦、阿比多尔、伐昔洛韦等);抗结核药。
- 剔除规则由
group_lists.json中抗菌药物组的 exclude_form 维护,与平台计数不一致时核对品种后调整。
三、控制目标
二级医院门诊抗菌药物使用率 ≤20%(以当年卫生健康行政部门要求为准)。
四、分级管理要点
- 按省级抗菌药物临床应用分级管理目录分为非限制使用级、限制使用级、特殊使用级。
- 门诊不得使用特殊使用级抗菌药物。
- 越级使用需有相应权限医师处方并留存依据;点评发现越级开具按"无正当理由"情形记录。
附录D:脚本与药品识别库(代码)
以下代码在有Python执行环境时使用;纯对话场景下可仅依据上述规则口径人工执行。
D1. scripts/parse_prescriptions.py
#!/usr/bin/env python3
"""处方用药情况文本解析器。
将点评导出处方 Excel 中"处方用药情况"列的多行文本解析为结构化药品记录。
行格式(来自医院HIS导出):序号 药品名 规格 用法 频次 单次剂量 总量 金额元
示例:1 磷酸奥司他韦胶囊 75mg/粒 口服 Bid 75mg 4粒 4元
用法:
from parse_prescriptions import load_prescriptions, parse_drug_line
df = load_prescriptions("处方.xlsx") # 处方级 DataFrame,含 drugs 列表列
"""
import re
import pandas as pd
FREQ_PATTERN = re.compile(
r"^(Qd|Bid|Tid|Qid|Qn|Qm|Qod|Qw|Biw|Tiw|Prn|Sos|St|Q\d+h|Q\d+d)"
r"(早|午|晚|早午|早中晚|下午|睡前|必要时)?$",
re.IGNORECASE,
)
# 规格特征:含"/"(75mg/粒),或 数字+单位(+xN包装)(1片、10mlx10支、0.2gx36s、60ml:2%/瓶),
# 或浓度+装量连写(10%10g、10g1%)
SPEC_PATTERN = re.compile(
r"^([\d.]+\s*(mg|g|ml|ug|μg|IU|iu|%|片|支|盒|袋|丸|瓶|揿|s|粒|枚|贴|滴|喷|板)"
r"([x::].*)?|[\d.]+%[\d.]+(g|ml)|[\d.]+(g|ml)[\d.]+%)$",
re.IGNORECASE,
)
def parse_drug_line(line):
"""解析单行用药文本,返回 dict;解析失败返回 None(调用方保留原文)。"""
line = line.strip()
if not line:
return None
tokens = line.split()
if len(tokens) < 7 or not tokens[0].isdigit():
return None
money = tokens[-1]
if not money.endswith("元"):
return None
# 频次固定在倒数第4位(剂量/总量/金额之后),不匹配则就近搜索
freq_idx = None
for i in range(len(tokens) - 4, 0, -1):
if FREQ_PATTERN.match(tokens[i]):
freq_idx = i
break
if freq_idx is None or freq_idx + 3 >= len(tokens):
return None
# 规格:频次之前、药名之后,从右向左找最后一个符合规格特征或含"/"的 token
spec_idx = None
for i in range(freq_idx - 1, 0, -1):
if "/" in tokens[i] or SPEC_PATTERN.match(tokens[i]):
spec_idx = i
break
if spec_idx is None:
return None
return {
"序号": int(tokens[0]),
"药品名称": " ".join(tokens[1:spec_idx]),
"规格": tokens[spec_idx],
"用法": " ".join(tokens[spec_idx + 1 : freq_idx]),
"频次": tokens[freq_idx],
"单次剂量": tokens[freq_idx + 1],
"总量": tokens[freq_idx + 2],
"金额": float(money[:-1]) if money[:-1].replace(".", "", 1).isdigit() else None,
"原文": line,
}
def parse_prescription_text(text):
"""解析整张处方的用药情况文本,返回药品 dict 列表(含未解析行的兜底记录)。"""
drugs = []
for line in str(text).strip().split("\n"):
if not line.strip():
continue
rec = parse_drug_line(line)
if rec is None:
rec = {"药品名称": line.strip(), "原文": line.strip(), "解析失败": True}
drugs.append(rec)
return drugs
def load_prescriptions(path, sheet_name=0, header=1):
"""读取点评处方 Excel。
默认 header=1(第2行为列名:序号/处方日期/年龄/诊断/处方用药情况/点评意见),
适配医院HIS导出格式;若导出格式不同,调整 header 参数。
返回处方级 DataFrame,新增 drugs(结构化药品列表)与 药品数 两列。
"""
df = pd.read_excel(path, sheet_name=sheet_name, header=header)
df.columns = [str(c).strip() for c in df.columns]
df = df[df["诊断"].notna() | df["处方用药情况"].notna()].reset_index(drop=True)
df["drugs"] = df["处方用药情况"].apply(parse_prescription_text)
df["药品数"] = df["drugs"].apply(len)
return df
if __name__ == "__main__":
import sys
df = load_prescriptions(sys.argv[1])
total_lines = df["drugs"].apply(len).sum()
failed = df["drugs"].apply(lambda ds: sum(1 for d in ds if d.get("解析失败"))).sum()
print(f"处方 {len(df)} 张,药品行 {total_lines} 条,解析失败 {failed} 条")
D2. scripts/batch_review.py
#!/usr/bin/env python3
"""处方批量分组与规则初筛。
流程:读入点评处方 Excel → 解析药品行 → 六类分组标记 → 规则引擎初筛疑似问题 →
输出带标记列的 Excel + 分组汇总统计。
初筛规则只负责"标疑点",不替代药师判断:命中规则的处方在"疑似问题"列写明
规则编号与描述,由点评药师逐条复核后填写正式"点评意见"。
用法:
python3 batch_review.py 处方.xlsx -o 点评结果.xlsx
python3 batch_review.py 处方.xlsx -o 点评结果.xlsx --sheet 门诊点评数据
"""
import argparse
import json
import re
from pathlib import Path
import pandas as pd
from parse_prescriptions import load_prescriptions
GROUPS = ["基本药物", "抗菌药物", "中成药", "糖皮质激素", "质子泵抑制剂", "麻精药品"]
LISTS_PATH = Path(__file__).parent / "group_lists.json"
# 感染相关诊断关键词(用于抗菌药物指征核查)
INFECTION_DX = re.compile(
r"感染|炎|脓|发热|发烧|热病|疖|痈|丹毒|蜂窝|败血|脓毒|菌血|结核|梅毒|淋病|"
r"支原体|衣原体|立克次|螺旋体|真菌|念珠|曲霉|寄生虫|蛔虫|蛲虫|钩虫|"
r"外伤|创伤|伤口|咬伤|刺伤|术后|切口|拔牙|种植|根尖|牙髓|冠周|龋齿|龋|"
r"咽喉|扁桃体|鼻窦|中耳|支气管|肺|尿路|尿道|膀胱|肾盂|前列腺|胆囊|胆管|"
r"阑尾|腹膜|盆腔|附睾|乳腺炎|角膜|结膜|睑腺|麦粒|胃肠炎|肠炎|腹泻|痢疾|"
r"幽门螺杆菌|Hp|HP|猩红|百日咳|白喉|破伤风|上呼吸道|感冒|流感|咽炎"
)
# 全身用糖皮质激素常见合理适应证关键词
GC_DX = re.compile(
r"过敏|哮喘|慢阻肺|COPD|鼻炎|皮炎|湿疹|荨麻疹|风湿|类风湿|狼疮|免疫|肾病|"
r"肾炎|紫癜|血小板|溶血|休克|移植|肿瘤|癌|化疗|水肿(喉|声)|喉炎|喘憋|"
r"痛风|关节|神经炎|面神经|带状疱疹|天疱疮|皮肌炎|干燥|溃疡性结肠|克罗恩"
)
# 糖皮质激素全身给药用法规格提示
GC_SYSTEMIC_ROUTE = re.compile(r"口服|注射|静|VD|iv|IV|im|IM|雾化|吸入|肌注")
# PPI 常见适应证关键词
PPI_DX = re.compile(
r"胃炎|胃食管|反流|食管炎|溃疡|十二指肠|消化不良|腹痛|胃痛|胃胀|呕血|黑便|"
r"幽门螺杆菌|Hp|HP|应激|消化道出血|糜烂|Barrett|巴雷特|嗳气|反酸|烧心|恶心|呕吐"
)
# 重复用药药理类别(同组内≥2个命中词即提示)
DUP_CLASSES = {
"NSAIDs": ["布洛芬", "双氯芬酸", "塞来昔布", "依托考昔", "洛索洛芬", "尼美舒利", "美洛昔康", "吲哚美辛", "萘普生", "赖氨匹林", "氟比洛芬"],
"抗组胺药": ["氯雷他定", "西替利嗪", "酮替芬", "依匹斯汀", "氯苯那敏", "赛庚啶", "苯海拉明", "氮卓斯汀", "非索非那定", "地氯雷他定", "左西替利嗪"],
"他汀类": ["阿托伐他汀", "瑞舒伐他汀", "辛伐他汀", "匹伐他汀", "普伐他汀", "氟伐他汀", "洛伐他汀"],
"ARB": ["缬沙坦", "厄贝沙坦", "氯沙坦", "替米沙坦", "奥美沙坦", "阿利沙坦", "坎地沙坦"],
"复方感冒药": ["氨酚伪麻", "双扑伪麻", "氨酚麻美", "氨咖黄敏", "酚麻美敏", "氨酚烷胺"],
}
AGE_PATTERN = re.compile(r"(\d+(?:\.\d+)?)\s*(岁|月|天|日|周)")
def parse_age_years(text):
m = AGE_PATTERN.search(str(text))
if not m:
return None
v, unit = float(m.group(1)), m.group(2)
if unit == "岁":
return v
if unit == "月":
return v / 12
return v / 365
def match_group(name, cfg, count_subgroups=None):
"""判断药品是否命中某分组。
subgroups 型分组(麻精药品):返回命中的亚组名;指定 count_subgroups 时,
只有命中这些亚组才计入分组(专项统计口径=麻醉药品+第一类精神药品),
其余亚组(精二、含特殊药品复方制剂)仅供规则引擎监控预警。
"""
if cfg.get("匹配方式") == "subgroups":
for sub, kws in cfg.items():
if sub in ("匹配方式", "备注"):
continue
if any(k in name for k in kws):
if count_subgroups is not None and not any(sub.startswith(c) for c in count_subgroups):
return None
return sub
return None
names = cfg.get("names")
if names and name in names:
return True
kws = cfg.get("keywords", [])
if any(k in name for k in kws):
for form in cfg.get("exclude_form", []):
if form in name:
return None
return True
return None
MJ_COUNT_SUBGROUPS = ("麻醉药品", "第一类精神药品")
def classify_prescription(drugs, lists):
"""返回 (命中分组列表, 各组命中药品 dict)。"""
hit = {}
for d in drugs:
name = d.get("药品名称", "")
name_clean = re.sub(r"^\([^)]*\)", "", name) # 去商品名前缀括号
for g in GROUPS:
kw = {"count_subgroups": MJ_COUNT_SUBGROUPS} if g == "麻精药品" else {}
r = match_group(name_clean, lists[g], **kw) or match_group(name, lists[g], **kw)
if r:
hit.setdefault(g, set()).add(name)
return sorted(hit), hit
def estimate_days(d):
"""按 总量 ÷(单次剂量 × 每日次数)估算用药天数,无法估算返回 None。"""
freq_map = {"qd": 1, "qn": 1, "qm": 1, "bid": 2, "tid": 3, "qid": 4, "qod": 0.5}
try:
f = freq_map.get(re.match(r"[A-Za-z]+", d["频次"]).group(0).lower())
if not f:
return None
dose = float(re.match(r"[\d.]+", d["单次剂量"]).group(0))
dose_unit = re.sub(r"^[\d.]+", "", d["单次剂量"])
total = float(re.match(r"[\d.]+", d["总量"]).group(0))
total_unit = re.sub(r"^[\d.]+", "", d["总量"])
if dose == 0 or dose_unit != total_unit:
return None
return round(total / (dose * f), 1)
except (KeyError, AttributeError, ValueError, ZeroDivisionError):
return None
def screen_rules(row, lists):
"""规则引擎:对单张处方返回疑似问题列表。"""
flags = []
drugs = row["drugs"]
dx = str(row.get("诊断", ""))
names = [d.get("药品名称", "") for d in drugs]
age = parse_age_years(row.get("年龄", ""))
parsed = [d for d in drugs if not d.get("解析失败")]
unparsed = [d for d in drugs if d.get("解析失败")]
if unparsed:
flags.append("R0 药品行解析失败,需人工核对用法用量:" + ";".join(d["原文"] for d in unparsed))
# R1 处方药品数>5种(处方管理办法:每张处方不得超过5种药品)
if len(drugs) > 5:
flags.append(f"R1 单张处方{len(drugs)}种药品,超过5种上限")
# R2 抗菌药物指征核查
abx = [d for d in parsed if match_group(re.sub(r"^\([^)]*\)", "", d["药品名称"]), lists["抗菌药物"])
or match_group(d["药品名称"], lists["抗菌药物"])]
if abx and not INFECTION_DX.search(dx):
flags.append("R2 使用抗菌药物但诊断未见感染相关描述,核查用药指征:" + "、".join(d["药品名称"] for d in abx))
# R3 儿童用药禁忌
if age is not None:
for d in parsed:
n = d["药品名称"]
if age < 12 and "尼美舒利" in n:
flags.append(f"R3 尼美舒利禁用于12岁以下儿童(患者{row['年龄']})")
if age < 18 and re.search(r"沙星", n) and not re.search(r"滴眼|滴耳", n):
flags.append(f"R3 全身用氟喹诺酮类不推荐18岁以下使用({n},患者{row['年龄']})")
if age < 8 and re.search(r"多西环素|米诺环素|四环素", n):
flags.append(f"R3 四环素类禁用于8岁以下儿童({n},患者{row['年龄']})")
if age < 2 and re.search(r"异丙嗪|喷托维林", n):
flags.append(f"R3 {n}慎/禁用于2岁以下儿童(患者{row['年龄']})")
# R4 重复用药(同类≥2种)
for cls, kws in DUP_CLASSES.items():
hit = [n for n in names if any(k in n for k in kws)]
if len(hit) >= 2:
flags.append(f"R4 疑似重复用药({cls}):" + "、".join(hit))
tcm_hit = [n for n in names if n in lists["中成药"]["names"]]
if len(tcm_hit) >= 3:
flags.append(f"R4 中成药联用≥3种,核查辨证与功能主治重叠:" + "、".join(tcm_hit))
# R5 全身用糖皮质激素指征
for d in parsed:
n = re.sub(r"^\([^)]*\)", "", d["药品名称"])
if (match_group(n, lists["糖皮质激素"]) and d.get("用法")
and GC_SYSTEMIC_ROUTE.search(d["用法"]) and not GC_DX.search(dx)):
flags.append(f"R5 全身用糖皮质激素({d['药品名称']})诊断中未见常见适应证描述,核查指征")
# R6 PPI 指征
for d in parsed:
n = re.sub(r"^\([^)]*\)", "", d["药品名称"])
if match_group(n, lists["质子泵抑制剂"]) and not PPI_DX.search(dx):
flags.append(f"R6 使用PPI/P-CAB({d['药品名称']})诊断中未见酸相关疾病描述,核查指征")
# R7 麻精/重点监控药品天数核查(精二口服一般≤7日常用量)
for d in parsed:
n = re.sub(r"^\([^)]*\)", "", d["药品名称"])
sub = match_group(n, lists["麻精药品"])
if sub:
days = estimate_days(d)
if sub.startswith("第二类精神药品") and days and days > 7:
flags.append(f"R7 精二药品{d['药品名称']}估算用量约{days}天,超过7日常用量")
elif sub == "麻醉药品" and days and days > 3 and "注射" in str(d.get("规格", "")):
flags.append(f"R7 麻醉药品注射剂{d['药品名称']}用量偏大(约{days}天),核查处方限量")
# R8 无诊断或诊断过简
if not dx or dx in ("nan", "无", "开药", "购药", "复诊开药"):
flags.append("R8 诊断缺失或仅为开药描述,不符合处方书写规范")
# R9 诊断与药品完全无关联的兜底提示(中药注射剂、辅助用药重点品种)
for d in parsed:
if re.search(r"注射液", d["药品名称"]) and re.search(r"丹参|血栓通|血塞通|银杏|参麦|生脉|疏血通", d["药品名称"]):
flags.append(f"R9 中药注射剂({d['药品名称']})按重点监控品种核查适应证与溶媒")
return flags
def summarize(df):
"""打印分组汇总统计(门诊口径:含门诊抗菌药物使用率,不含DDDs指标)。"""
total = len(df)
print(f"\n===== 专项分组汇总(共{total}张处方)=====")
for g in GROUPS:
col = f"分组_{g}"
n = df[col].apply(bool).sum()
label = "麻、精一药品" if g == "麻精药品" else g
print(f"{label}: {n} 张,处方率 {n/total:.2%}")
abx = df["分组_抗菌药物"].apply(bool).sum()
print(f"\n门诊抗菌药物使用率: {abx/total:.2%}({abx}/{total},二级医院控制目标≤20%)")
lists = json.loads(LISTS_PATH.read_text(encoding="utf-8"))
sub_counts = {}
for drugs in df["drugs"] if "drugs" in df.columns else []:
for d in drugs:
s = match_group(re.sub(r"^\([^)]*\)", "", d.get("药品名称", "")), lists["麻精药品"])
if s:
sub_counts[s] = sub_counts.get(s, 0) + 1
if sub_counts:
print("重点监控预警(不计入麻精专项): " + ";".join(f"{k} {v}条" for k, v in sub_counts.items()))
flagged = df["疑似问题"].apply(bool).sum()
print(f"\n初筛命中疑似问题处方: {flagged} 张({flagged/total:.2%})")
rule_counts = {}
for s in df["疑似问题"]:
for item in s:
r = item.split()[0]
rule_counts[r] = rule_counts.get(r, 0) + 1
for r, c in sorted(rule_counts.items()):
print(f" {r}: {c} 条")
def dept_stats(df):
"""若导出含科室列,返回科室分布 DataFrame(计数+占比),否则返回 None。"""
col = next((c for c in df.columns if "科室" in c), None)
if col is None:
return None
s = df[col].fillna("未填写").value_counts()
out = pd.DataFrame({"处方科室名称": s.index, "计数": s.values})
out["占比"] = (out["计数"] / len(df)).apply(lambda x: f"{x:.1%}")
return out
def main():
ap = argparse.ArgumentParser()
ap.add_argument("input", help="处方Excel路径")
ap.add_argument("-o", "--output", required=True, help="输出Excel路径")
ap.add_argument("--sheet", default=0, help="工作表名或序号")
ap.add_argument("--header", type=int, default=1, help="列名所在行(0起,HIS导出通常为1)")
args = ap.parse_args()
lists = json.loads(LISTS_PATH.read_text(encoding="utf-8"))
sheet = int(args.sheet) if str(args.sheet).isdigit() else args.sheet
df = load_prescriptions(args.input, sheet_name=sheet, header=args.header)
group_cols, flag_cols = [], []
for _, row in df.iterrows():
groups, _ = classify_prescription(row["drugs"], lists)
group_cols.append(groups)
flag_cols.append(screen_rules(row, lists))
for g in GROUPS:
df[f"分组_{g}"] = [["√"] if g in gc else [] for gc in group_cols]
df[f"分组_{g}"] = df[f"分组_{g}"].apply(lambda x: "√" if x else "")
df["分组汇总"] = ["、".join(gc) for gc in group_cols]
df["疑似问题"] = ["\n".join(fc) for fc in flag_cols]
if "点评意见" not in df.columns:
df["点评意见"] = ""
out = df.drop(columns=["drugs"])
dept = dept_stats(out)
if dept is not None:
with pd.ExcelWriter(args.output) as w:
out.to_excel(w, index=False, sheet_name="点评明细")
dept.to_excel(w, index=False, sheet_name="科室分布")
else:
out.to_excel(args.output, index=False)
print(f"已输出: {args.output}")
df["疑似问题"] = flag_cols
for g in GROUPS:
df[f"分组_{g}"] = [g in gc for gc in group_cols]
summarize(df)
if __name__ == "__main__":
main()
D3. scripts/group_lists.json
{
"版本": "2026-06",
"维护说明": "本文件为六类分组的药品识别库,按本院在用药品维护。匹配方式:keywords=药名包含任一关键词即命中;names=药名完全匹配命中;exclude_form=药品名称含这些剂型词时不计入该组(用于剔除局部外用制剂)。新增药品时直接在对应数组追加即可,无需改代码。目录依据以国家最新版为准:基本药物目录、抗菌药物分级管理目录(省级)、麻醉药品和精神药品目录。",
"基本药物": {
"匹配方式": "keywords",
"备注": "以下为常用基药通用名起始清单。若HIS导出已带基药标识列,优先用标识列;否则按本院执行的国家基本药物目录增补keywords。",
"keywords": [
"二甲双胍", "格列美脲", "格列齐特", "阿卡波糖", "伏格列波糖", "吡格列酮",
"氨氯地平", "硝苯地平", "非洛地平", "缬沙坦", "厄贝沙坦", "氯沙坦", "培哚普利", "贝那普利",
"美托洛尔", "比索洛尔", "阿替洛尔", "普萘洛尔", "氢氯噻嗪", "吲达帕胺", "呋塞米", "螺内酯",
"阿托伐他汀", "瑞舒伐他汀", "辛伐他汀", "匹伐他汀", "非诺贝特",
"阿司匹林", "氯吡格雷", "华法林", "单硝酸异山梨酯", "地高辛",
"头孢呋辛", "头孢克洛", "头孢克肟", "头孢拉定", "头孢唑林", "头孢曲松",
"阿莫西林", "青霉素", "苯唑西林", "左氧氟沙星", "阿奇霉素", "罗红霉素", "克拉霉素", "红霉素",
"克林霉素", "甲硝唑", "多西环素", "奥司他韦", "恩替卡韦", "氟康唑", "特比萘芬", "阿苯达唑",
"布洛芬", "对乙酰氨基酚", "双氯芬酸", "秋水仙碱",
"氯雷他定", "西替利嗪", "酮替芬", "氯苯那敏", "孟鲁司特",
"氨溴索", "溴己新", "羧甲司坦", "茶碱", "沙丁胺醇", "布地奈德", "异丙托溴铵", "丙卡特罗",
"奥美拉唑", "雷尼替丁", "法莫替丁", "铝碳酸镁", "硫糖铝", "枸橼酸铋钾", "胶体果胶铋",
"蒙脱石", "多潘立酮", "莫沙必利", "乳果糖", "口服补液盐", "山莨菪碱", "间苯三酚",
"泼尼松", "地塞米松", "甲泼尼龙", "氢化可的松",
"甲巯咪唑", "丙硫氧嘧啶", "左甲状腺素",
"叶酸", "维生素B1", "维生素B2", "维生素B6", "维生素C", "维生素D2", "碳酸钙D3", "骨化三醇", "阿法骨化醇",
"氯化钠注射液", "葡萄糖注射液", "灭菌注射用水", "利多卡因", "破伤风抗毒素",
"特拉唑嗪", "坦索罗辛", "非那雄胺", "卡马西平", "甲氨蝶呤", "别嘌醇", "苯溴马隆", "莫匹罗星", "炉甘石", "尿素乳膏", "利可君", "肌苷", "葡醛内酯", "联苯苄唑"
]
},
"抗菌药物": {
"匹配方式": "keywords+exclude_form",
"备注": "全身用抗菌药物(含抗真菌药)。滴眼/滴耳/外用软膏/阴道栓等局部制剂不计入抗菌药物组;抗病毒药(奥司他韦、恩替卡韦、阿比多尔、伐昔洛韦等)不计入。小檗碱、大蒜素等植物来源抗菌药是否计入按省级分级目录口径。",
"keywords": [
"头孢", "阿莫西林", "青霉素", "苯唑西林", "氨苄西林", "哌拉西林", "美洛西林",
"左氧氟沙星", "氧氟沙星", "诺氟沙星", "环丙沙星", "莫西沙星",
"阿奇霉素", "罗红霉素", "克拉霉素", "红霉素", "环酯红霉素", "乙酰螺旋霉素",
"克林霉素", "林可霉素", "甲硝唑", "替硝唑", "奥硝唑",
"多西环素", "米诺环素", "四环素", "磺胺", "复方新诺明", "呋喃妥因", "磷霉素",
"万古霉素", "去甲万古霉素", "替考拉宁", "利奈唑胺", "庆大霉素", "阿米卡星", "妥布霉素",
"氟康唑", "伊曲康唑", "伏立康唑", "卡泊芬净", "两性霉素", "制霉菌素", "特比萘芬", "硝呋太尔"
],
"exclude_form": ["滴眼液", "滴耳液", "乳膏", "软膏", "凝胶", "栓", "洗液", "洗剂", "搽剂", "喷雾剂(外用)", "含漱", "眼膏", "贴"]
},
"中成药": {
"匹配方式": "names",
"备注": "本院在用中成药品种清单(按国药准字Z口径,含维药、苗药等民族药及含化药成分的中成药如维C银翘片)。新药入库后在此追加品名。",
"names": [
"裸花紫珠片", "肺力咳合剂", "清开灵胶囊", "清开灵颗粒", "小儿热速清颗粒", "香菊片", "鼻炎片(中联)",
"肿痛安胶囊", "金振口服液", "玄麦甘桔胶囊", "四磨汤口服液", "致康胶囊", "元胡止痛滴丸",
"口炎清颗粒", "复方丹参滴丸", "复方丹参片", "寒喘祖帕颗粒", "小儿柴桂退热口服液", "比拜克胶囊",
"复方血栓通胶囊", "大活络胶囊", "抗病毒口服液", "金天格胶囊", "祖卡木颗粒", "甘桔冰梅片",
"金叶败毒颗粒", "清热八味胶囊", "活血止痛胶囊", "腹可安片", "鼻炎康片", "小儿消积止咳口服液",
"血脂康胶囊", "金蝉止痒胶囊", "妇炎康复胶囊", "乌灵胶囊", "血塞通胶囊", "润燥止痒胶囊",
"鼻窦炎口服液", "脑栓通胶囊", "坤泰胶囊", "尿毒清颗粒", "玉屏风颗粒", "脉血康胶囊",
"伤科接骨片", "银丹心泰滴丸", "醒脾养儿颗粒", "杏贝止咳颗粒", "加味藿香正气丸", "稳心颗粒",
"荜铃胃痛颗粒", "瘀血痹片", "通心络胶囊", "舒泌通胶囊", "地奥心血康胶囊", "小金丸", "银杏叶片",
"保济丸", "咳特灵胶囊", "益气维血片", "麝香追风止痛膏", "固本益肠片", "消炎利胆片",
"少腹逐瘀胶囊", "消痛贴膏", "胃复春胶囊", "乳块消颗粒", "芪苈强心胶囊", "板蓝根颗粒",
"枣仁安神胶囊", "参柏洗液", "坤复康片", "固肾安胎丸", "芪参益气滴丸", "七叶神安片",
"尿石通丸", "都梁软胶囊", "安胃疡胶囊", "至灵胶囊", "脉管复康片", "化痔栓", "宫炎平胶囊",
"镇痛活络酊", "六神丸", "银黄颗粒", "和血明目片", "滑膜炎片", "心宝丸", "湿润烧伤膏",
"大黄蟅虫片", "缩泉胶囊", "正清风痛宁缓释片", "急支糖浆", "蛇胆川贝液", "松龄血脉康胶囊",
"参松养心胶囊", "强力定眩胶囊", "宁泌泰胶囊", "双石通淋胶囊", "维C银翘片",
"儿肤康搽剂", "百安洗液", "西帕依固龈液", "开喉剑喷雾剂", "马应龙麝香痔疮膏",
"骨通贴膏(天和)", "通络祛痛膏", "代温灸膏", "保妇康栓"
]
},
"糖皮质激素": {
"匹配方式": "keywords+exclude_form",
"备注": "专项统计口径为全身用(口服/注射/吸入雾化)。乳膏、软膏、眼膏、滴眼液等局部外用制剂不计入专项处方数;糠酸莫米松鼻喷雾剂等鼻用制剂是否计入按本院平台口径执行(本院平台不计入,故列入exclude_form)。",
"keywords": [
"泼尼松", "泼尼松龙", "地塞米松", "甲泼尼龙", "氢化可的松", "倍他米松",
"布地奈德", "糠酸莫米松", "氟米松", "卤米松", "曲安奈德", "氟替卡松", "倍氯米松", "可的松"
],
"exclude_form": ["乳膏", "软膏", "眼膏", "滴眼液", "洗剂", "洗液", "搽剂", "鼻喷雾剂", "鼻喷"]
},
"质子泵抑制剂": {
"匹配方式": "keywords",
"备注": "含PPI与P-CAB(伏诺拉生、替戈拉生等钾离子竞争性酸阻滞剂,按同类管理)。",
"keywords": [
"奥美拉唑", "兰索拉唑", "泮托拉唑", "雷贝拉唑", "艾司奥美拉唑", "艾普拉唑",
"伏诺拉生", "替戈拉生"
]
},
"麻精药品": {
"匹配方式": "subgroups",
"备注": "专项统计口径严格按国家最新版《麻醉药品品种目录》《精神药品品种目录》执行=麻醉药品+第一类精神药品。丙泊酚、右美托咪定等舒适化麻醉用药非国家目录麻精品种,不计入麻精专项。第二类精神药品与含特殊药品复方制剂不计入专项处方数,仅用于R7规则重点监控预警。",
"麻醉药品": ["吗啡", "哌替啶", "芬太尼", "舒芬太尼", "瑞芬太尼", "羟考酮", "磷酸可待因", "可待因片", "罂粟碱", "阿片粉"],
"第一类精神药品": ["哌甲酯", "氯胺酮", "马吲哚"],
"第二类精神药品(仅规则监控)": [
"地西泮", "艾司唑仑", "阿普唑仑", "氯硝西泮", "劳拉西泮", "奥沙西泮", "硝西泮", "咪达唑仑",
"唑吡坦", "佐匹克隆", "右佐匹克隆", "苯巴比妥", "巴比妥", "曲马多", "氨酚待因",
"地佐辛", "布托啡诺", "喷他佐辛", "含可待因复方口服溶液", "复方地芬诺酯"
],
"含特殊药品复方制剂(仅规则监控)": ["可待因桔梗", "复方甘草", "氨酚伪麻", "双扑伪麻", "氨酚麻美"]
}
}