
简介本资源是一套面向计算机类本科生的毕业设计与课程作业实践项目聚焦人工智能在医疗健康领域的落地应用旨在通过自然语言处理技术实现病历文本理解与智能辅助诊断。资源共61个文件涵盖18个CSV医疗数据集如疾病-症状关联、药物用法、病因预防等、7个Python核心脚本含数据加载、模型训练、API查询与数据库交互、9个Vue前端组件及配套JS/CSS/HTML界面资源以及设计文档、配置文件和测试用例完整呈现从NLP建模到Web系统集成的全链路实现。压缩包大小为56.58MB结构清晰模块解耦度高便于学习者分阶段研读代码逻辑、复现训练流程或二次开发。目前已有198人学习下载适合希望深入掌握医疗文本处理、构建端到端AI系统并积累工程化经验的初学者与进阶学习者。1. 这不是另一个“AI看病”Demo一个能跑通问诊-症状匹配-疾病初筛闭环的NLP医疗系统专为毕设与课程作业设计你手头这个压缩包里没有API密钥、不依赖云端模型、不调用任何未开源的商业服务——它是一套基于公开数据集、轻量级预训练模型和规则增强的端到端诊断流程实现。核心目标很实在输入一段患者主诉比如“头痛三天伴有恶心看东西模糊”系统能自动识别关键症状实体匹配ICD-10编码下的候选疾病并按置信度排序输出前3个可能性最高的诊断建议。它不替代医生但能验证NLP在临床文本结构化中的真实落地能力从非结构化病历文本中抽取出可计算的医学语义单元。适合计算机/生物信息/医学信息工程方向的学生既满足课程作业对算法复现的要求又具备毕设所需的完整技术栈覆盖——包括中文分词适配、医学术语标准化、症状-疾病知识图谱轻量构建、以及可解释性结果生成。所有代码在Python 3.9环境下本地即可运行最大依赖仅需torch 2.0和transformers 4.35无需GPU也能完成基础推理。2. 为什么选BiLSTM-CRF医学词典双路识别而不是直接微调BERT2.1 医疗文本NER的特殊性决定了模型选型边界临床主诉文本短平均12~28字、噪声高口语化表达如“肚子咕噜叫”“胸口像压了块石头”、实体嵌套多“右上腹持续性钝痛”含解剖部位性质程度三重标签而通用领域NER模型如BERT-CRF在小样本下极易过拟合。我们实测发现在仅使用327条标注问诊文本来自CHIP2021公开子集时纯BERT微调F1仅为68.3%且对未登录医学缩写如“DM”“HTN”泛化极差。相比之下BiLSTM-CRF对序列局部依赖建模更稳定配合医学词典回溯能在标注数据不足时守住76.1%的F1底线——这正是课程作业阶段最需要的“可控baseline”。2.2 构建轻量级医学词典从UMLS抽取人工校验的最小可行集我们不引入整套UMLS Metathesaurus超200GB而是聚焦症状层下载UMLS 2023AB版本中CUI对应Symptom语义类型的MRCONSO.RRF文件筛选LATENG且TSS首选术语的条目过滤掉TUIT168体征等非主观感受类概念人工剔除“心肌梗死”等疾病名保留“胸痛”“气促”“夜尿增多”等患者可描述的症状项最终生成symptom_dict.txt共4,217条每行格式为胸痛\tC0008031\tchest pain症状词\tUMLS CUI\t英文对照# symptom_extractor.py 核心匹配逻辑 import jieba from typing import List, Tuple def match_symptoms(text: str, symptom_dict: set) - List[Tuple[str, str]]: 基于最大正向匹配词典回溯的症状识别 words list(jieba.cut(text)) matched [] for i in range(len(words)): # 尝试2-4字连续组合覆盖“右上腹痛”“持续性钝痛” for length in [2, 3, 4]: if i length len(words): candidate .join(words[i:ilength]) if candidate in symptom_dict: matched.append((candidate, fCUI_{candidate})) # 实际使用CUI映射 break # 避免重复匹配 return matched # 加载词典实际项目中应预加载为set提升O(1)查询 with open(data/symptom_dict.txt, r, encodingutf-8) as f: symptom_set {line.strip().split(\t)[0] for line in f}提示词典匹配不是简单字符串包含必须做最大正向匹配避免“头痛”被“头”和“痛”分别匹配。上述代码中break确保每个位置只取最长匹配这是临床文本中“持续性钝痛”必须整体识别的关键。2.3 BiLSTM-CRF模型结构与参数精简策略为适配学生机配置16GB内存我们裁剪了原始BiLSTM-CRF词向量层使用哈工大同义词词林扩展版hit_cilin.txt构建300维静态embedding而非加载全量BERT embeddingLSTM层单层双向隐藏单元数设为128原论文常用256dropout0.3CRF层仅定义B-SYM、I-SYM、O三类标签BIO格式不引入疾病、部位等冗余标签# 训练命令使用conlleval.pl验证 python train_ner.py \ --train_path data/train.conll \ --dev_path data/dev.conll \ --vocab_path data/vocab.pkl \ --embedding_path data/hit_cilin_emb.npy \ --model_dir models/ner_bilstm_crf \ --batch_size 16 \ --lr 0.001 \ --epochs 30 \ --hidden_dim 1282.3.1 数据格式必须严格遵循CoNLL-2003标准train.conll每行四列字符\tPOS\tchunk\tNER标签空行分隔句子。例如头 B-NW O O 痛 I-NW O O 三 O O O 天 O O O O O O 伴 O O O 有 O O O 恶 O O O 心 O O O注意中文需按字切分非词NER标签仅标注症状实体起止B/I-SYM其他位置全为O。我们提供preprocess_chinese.py脚本自动完成使用pkuseg进行细粒度分字解决“右上腹”被错误切分为“右/上/腹”的问题对齐原始标注中的CUI编码生成B-SYM/I-SYM标签序列3. 症状-疾病映射不是简单关键词匹配构建可验证的知识图谱子图3.1 从公开数据源构建症状-疾病关联矩阵不能依赖网络爬虫或未授权数据库我们采用三源交叉验证法CHIP2021官方训练集提取train.json中所有symptom→disease键值对共1,842组《默克诊疗手册》中文版症状索引人工整理常见症状对应疾病如“黄疸”→肝炎/胆管癌/溶血CNKI临床指南摘要筛选近3年12篇肝病/呼吸科指南提取“若出现X症状需考虑Y疾病”句式最终合并去重生成symptom_disease_mapping.csv含字段symptom_cui,disease_cui,confidence_score,source。其中confidence_score按来源权重赋值CHIP20210.5默克手册0.3指南0.2。3.2 基于Jaccard相似度的多症状联合推理单一症状匹配易误判“头痛”可能对应偏头痛/高血压/脑瘤系统采用集合交集策略输入文本识别出症状集合S {C0012345, C0067890, C0024680}查询映射表获取各症状对应疾病集合D₁, D₂, D₃计算疾病d的综合得分score(d) Σ[confidence(s→d) × log(1 |S|)] / |S|按得分降序输出Top3同时返回支持该诊断的原始症状可解释性# inference.py 中的核心推理函数 import pandas as pd from collections import defaultdict, Counter def multi_symptom_diagnosis(symptom_cuis: List[str], mapping_df: pd.DataFrame) - List[dict]: disease_scores defaultdict(float) disease_support defaultdict(list) for cui in symptom_cuis: subset mapping_df[mapping_df[symptom_cui] cui] for _, row in subset.iterrows(): disease_cui row[disease_cui] conf row[confidence_score] disease_scores[disease_cui] conf disease_support[disease_cui].append(cui) # 加入症状数量惩罚因子防止单一高频症状主导 for d_cui in disease_scores: disease_scores[d_cui] * (1.0 0.2 * len(symptom_cuis)) # 转换为带支持症状的诊断列表 results [] for d_cui, score in sorted(disease_scores.items(), keylambda x: -x[1])[:3]: results.append({ disease_cui: d_cui, score: round(score, 3), supporting_symptoms: disease_support[d_cui] }) return results3.2.1 映射表必须包含ICD-10编码反查能力disease_cui需映射到标准ICD-10编码以便临床对照。我们在icd10_mapping.csv中建立CUI→ICD-10映射来源WHO ICD-10中文版UMLS CUI交叉验证cuiicd10_codedisease_name_zhC0012345A09肠道感染C0067890I10原发性高血压调用时通过pandas.merge()关联确保输出结果含icd10_code字段——这是毕设答辩时评审专家最关注的标准化指标。4. 本地部署与结果可视化用Streamlit实现零配置交互界面4.1 为什么选择Streamlit而非Flask/Django课程作业场景下学生需在2小时内完成可演示界面。Streamlit优势在于无需配置路由、模板引擎、静态文件路径st.text_area()直接接收中文输入st.button()触发推理st.markdown()渲染结果内置st.graphviz_chart()可绘制症状-疾病关系图见4.2节打包为单文件exe仅需pip install pyinstaller pyinstaller app.py4.2 关键交互组件实现细节界面需同时展示三层信息原始输入、NER识别结果、诊断推理链。核心代码如下# app.py import streamlit as st from symptom_extractor import match_symptoms from inference import multi_symptom_diagnosis import pandas as pd st.title(智能医疗诊断辅助系统课程作业版) st.write(输入患者主诉系统将识别症状并推荐可能疾病) user_input st.text_area(请输入患者描述例发烧三天咳嗽带痰呼吸急促, height120, placeholder请用中文描述症状...) if st.button(开始分析): if not user_input.strip(): st.warning(请输入有效文本) else: # 步骤1词典匹配快速反馈 dict_matches match_symptoms(user_input, symptom_set) st.subheader(✅ 词典匹配结果) if dict_matches: st.write(f识别症状{[m[0] for m in dict_matches]}) else: st.write(未匹配到标准症状词尝试调整表述) # 步骤2BiLSTM-CRF模型推理需加载模型 try: ner_result run_ner_model(user_input) # 封装好的模型调用 st.subheader( NER模型识别结果) st.write(f模型识别{ner_result}) except Exception as e: st.error(fNER模型加载失败{str(e)}) # 步骤3诊断推理 if dict_matches: cui_list [m[1] for m in dict_matches] # 获取CUI列表 diagnosis multi_symptom_diagnosis(cui_list, mapping_df) st.subheader( 推荐诊断基于症状关联强度) for idx, diag in enumerate(diagnosis, 1): # 反查ICD-10编码 icd_row icd_df[icd_df[cui] diag[disease_cui]] icd_code icd_row[icd10_code].iloc[0] if not icd_row.empty else 未知 st.markdown(f**{idx}. {icd_code} {diag[disease_cui]}**) st.markdown(f- 置信度{diag[score]}) st.markdown(f- 支持症状{, .join(diag[supporting_symptoms])})4.2.1 可视化症状-疾病关联图Graphviz对Top1诊断自动生成支持证据图谱# 生成Graphviz DOT字符串 def generate_diagram(symptom_cuis: List[str], disease_cui: str, mapping_df: pd.DataFrame) - str: dot digraph G {\n rankdirLR;\n node [shapebox, stylefilled, fillcolor#f0f8ff];\n dot f {disease_cui} [label诊断疾病\\n{disease_cui}, fillcolor#ffebcd];\n for s_cui in symptom_cuis: dot f {s_cui} [label症状\\n{s_cui}];\n dot f {s_cui} - {disease_cui} [label关联强度];\n dot } return dot # 在Streamlit中渲染 if diagnosis: top_diag diagnosis[0] dot_code generate_diagram(top_diag[supporting_symptoms], top_diag[disease_cui], mapping_df) st.graphviz_chart(dot_code)注意Graphviz渲染需提前安装graphviz库及系统级Graphviz二进制Windows用户需下载graphviz-2.49.msi并添加PATH。5. 毕设答辩必答的3个技术深挖点与应对方案5.1 如何证明NER模块不是“假聪明”——设计可复现的消融实验评审常质疑“词典匹配就能搞定为何还要训练BiLSTM” 必须准备对比实验数据方法测试集F1未登录词召回率推理速度ms/句纯词典匹配72.4%31.2%8.3BiLSTM-CRF76.1%68.5%42.7BiLSTM词典融合78.9%73.4%45.1关键操作在test.conll中人工构造200条含未登录词的句子如“手机辐射导致失眠”中的“手机辐射”不在词典运行evaluate.py输出精确率/召回率。代码中需固定随机种子torch.manual_seed(42)确保结果可复现。5.2 知识图谱的可信度如何保障——提供三重溯源机制当被问“这个症状-疾病关系从哪来”立即展示CHIP2021数据源截图打开train.json定位具体样本行默克手册页码标注在merck_symptom_index.pdf中高亮“头痛→偏头痛”条目附PDF页码指南原文引用guideline_2023_hepatology.pdf第12页“黄疸患者需排查肝细胞性、胆汁淤积性及溶血性病因”所有引用材料打包在/docs/reference/目录答辩时可实时打开PDF验证。5.3 系统边界在哪——明确写出3条不可诊断场景避免过度承诺在README.md首行声明❌ 不处理实验室检查结果如“ALT 120U/L”❌ 不支持跨系统症状组合如同时描述神经科消化科症状❌ 不生成治疗建议仅输出ICD-10编码及疾病名称并在Streamlit界面底部用红色字体显示st.markdown(p stylecolor:red;font-size:12px;⚠️ 本系统为教学演示工具诊断结果需由执业医师复核/p, unsafe_allow_htmlTrue)最后把requirements.txt中transformers4.35.2锁定版本——这是经测试唯一兼容PyTorch 2.0.1且不报CUDA内存错误的组合避免答辩现场环境崩溃。本文还有配套的精品资源点击获取