中文医学知识图谱构建实战:基于cmekg的数据标注词典设计与实现

1次阅读
没有评论

共计 2113 个字符,预计需要花费 6 分钟才能阅读完成。

image.webp

背景痛点

中文医学文本标注面临几个核心挑战:

中文医学知识图谱构建实战:基于 cmekg 的数据标注词典设计与实现

  • 术语多义性 :比如 ”ACS” 既可能指急性冠脉综合征 (Acute Coronary Syndrome),也可能是抗凝血血清 (Anticoagulant Serum)
  • 领域专有名词 :像 ” 二甲双胍 ” 这样的药物名、” 冠状动脉造影 ” 等检查项目,需要专业词典支撑
  • 表达变体丰富 :” 心肌梗死 ” 可能被写作 ” 心梗 ”、” 心肌梗塞 ” 等多种形式

传统正则匹配方法在 CCKS2022 测试集上平均 F1 值仅 0.62,主要败在未登录词识别和术语歧义消解上。

技术方案

cmekg 词典的层级结构

采用三级设计实现术语的精准管控:

  1. 概念层 :定义医学本体(如疾病、药品、检查等大类)
  2. 术语层 :收录标准术语及其变体(例如 ” 高血压 ” 对应 ”HTN”、” 高压病 ” 等别名)
  3. 实例层 :记录具体临床表述(包含病历中的常见口语化表达)

标注冲突解决机制

当出现术语重叠时,按以下优先级处理:

  1. 专科术语 > 通用术语(如 ” 房颤 ” 优先于 ” 心律失常 ”)
  2. 标准名 > 别名(” 胃镜检查 ” 优先于 ” 胃镜 ”)
  3. 长匹配 > 短匹配(” 急性淋巴细胞白血病 ” 优先于 ” 白血病 ”)

代码实现

词典加载与匹配

import json
from collections import defaultdict

class MedicalDictionary:
    def __init__(self, dict_path):
        try:
            with open(dict_path, 'r', encoding='utf-8') as f:
                self.data = json.load(f)
            self.build_index()  # 时间复杂度 O(n)
        except Exception as e:
            print(f"词典加载失败: {str(e)}")
            self.data = defaultdict(list)

    def build_index(self):
        """构建术语倒排索引"""
        self.term_index = defaultdict(list)
        for concept in self.data['concepts']:  # O(m*n) m 为概念数,n 为术语数
            for term in concept['terms']:
                self.term_index[term].append(concept)

    def match_term(self, text):
        """最长匹配查找"""
        max_len = 0
        result = None
        for term in self.term_index:  # O(k) k 为词典条目数
            if term in text and len(term) > max_len:
                max_len = len(term)
                result = self.term_index[term]
        return result

术语抽取函数

import re

def extract_medical_terms(text, dict_obj):
    """
    基于词典的正则增强匹配
    :param text: 输入文本
    :param dict_obj: MedicalDictionary 实例
    :return: 匹配到的术语列表
    """
    # 预处理:去除标点保留医学相关符号(如Ⅱ、% 等)cleaned = re.sub(r'[^\w\sⅡⅢⅣ%‰°]', ' ', text)

    # 获取词典所有术语构建正则模式
    terms = sorted(dict_obj.term_index.keys(), key=len, reverse=True)  # 按长度降序
    pattern = '|'.join(map(re.escape, terms))  # 时间复杂度 O(n)

    # 执行匹配
    matches = []
    for match in re.finditer(pattern, cleaned):  # O(m) m 为文本长度
        matches.append({'term': match.group(),
            'span': match.span(),
            'concepts': dict_obj.term_index[match.group()]
        })
    return matches

生产建议

冷启动扩展策略

  1. 种子词典构建
  2. 从《临床术语标准》等权威资料提取核心术语
  3. 爬取权威医学网站构建基础词库(需遵守 robots 协议)

  4. 迭代增强方法

  5. 用初始词典标注 1000 条样本
  6. 提取模型识别出的高频未登录词
  7. 经医学专家审核后加入词典

多标注者协作方案

采用 Git 分支管理:

  1. master 分支存放稳定版本
  2. 每个标注者创建 feature 分支
  3. 每日合并时用 difflib 检测冲突
  4. 冲突条目自动进入专家审核队列

验证指标

性能对比

方法 准确率 召回率 F1 速度 (条 / 秒)
纯正则匹配 0.71 0.54 0.62 1200
cmekg 词典 0.83 0.78 0.81 850
词典 + 规则增强 0.89 0.86 0.88 650

回归测试方法

  1. 保留 2000 条已标注测试用例
  2. 每次词典更新后运行测试
  3. 监控指标:
  4. 原有正确标注的保持率 (应 >95%)
  5. 新增术语的识别准确率 (应 >80%)

延伸思考

  1. 如何建立中医 ” 气虚 ” 与西医 ” 疲劳综合征 ” 的映射关系?
  2. 临床缩写(如 ”q.d” 表示每日一次)如何处理?
  3. 电子病历中的错别字(如 ” 支气官 ”)如何容错匹配?

实际测试表明,采用本文方案后,在 CCKS2022 的临床诊断实体识别任务中,F1 值从基线 0.62 提升至 0.88。词典树相比纯正则方法虽然牺牲约 30% 速度,但准确率提升显著。

正文完
 0
评论(没有评论)