ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

中文电子病历命名实体识别实战:CCKS2019医渡云4k数据集全流程解析

中文电子病历命名实体识别实战:CCKS2019医渡云4k数据集全流程解析 简介命名实体识别NER是自然语言处理中的基础任务旨在从非结构化文本中抽取具有特定意义的实体。在医疗领域电子病历包含大量症状、疾病、检查和治疗信息对临床决策支持与病历结构化至关重要。然而中文病历文本存在字词不规范、句式碎片化等挑战通用模型难以直接适配。BERT与CRF的结合为序列标注提供了稳健的解决方案通过引入标签转移约束可有效提升实体边界识别的准确性。以CCKS2019医渡云4k电子病历数据集为实践对象系统梳理了从数据预处理、模型选型、训练调优到bad case分析的全流程并分享了滑窗切分、对抗训练等优化技巧为构建中文医疗文本处理Pipeline提供参考。1. 这个数据集为什么值得折腾CCKS2019医渡云4k病历的项目背景做中文命名实体识别NER做到一定阶段很多人会卡在一个尴尬的位置通用领域的新闻、百科数据跑得再溜一到垂直行业就现出原形。我当初入坑医疗文本处理第一感觉就是——之前那些模型在病历上水土不服得厉害。电子病历这玩意儿错字多、简称多、句式碎、指代乱和干净规整的通用语料完全是两个物种。所以当我看到CCKS2019医渡云这个4k电子病历数据集第一时间就下了下来想用它把整套医疗文本NER的流程真正跑通一遍。这个数据集的正式名称是ccksyidu4k-ner.zip属于CCKS 2019评测任务的一部分。当年的任务聚焦于中文电子病历的命名实体识别由医渡云提供脱敏后的真实临床文本。所谓4k指的是带标注的训练样本大约4000份这些样本来自真实的出院记录、入院记录、病程记录等文本内容覆盖了症状、体征、疾病诊断、检查检验、治疗用药等关键临床信息。相比很多公开的英文医疗数据集比如i2b2系列这个数据集的优势在于是原生的中文临床文本不需要做翻译对齐也没有英文分词那一堆麻烦事。从实际价值来看这个数据集有几个不可替代的位置第一它是少数可以直接用于评测中文医疗NER模型的中型数据集规模不大不小单卡就能跑特别适合做算法对比和baseline搭建第二它带有明确的实体类别体系可以直接对接临床辅助决策、病历结构化、结构化录入等真实应用场景第三它的文本风格非常原生包含了很多临床真实语境中的缩写、口语化表达、不完整句式这恰恰是检验模型泛化能力的好材料。我当时决定写这篇博客一个重要原因是网上关于这个数据集的中文资料比较零散很多帖子只贴一个run起来的结果不讲数据形态、不讲标注细节、不讲踩坑过程。这篇文章的目标就是把我从拿到zip压缩包到调通模型、分析bad case、优化精度的整条链路上值得记录的东西都摊开来讲。无论你是刚入门NLP想做医疗方向、还是已经在做NER但想找一个垂直领域的数据集来验证模型这份内容都应该能帮你少走一些弯路。2. 打开压缩包之后数据格式、标注体系与文本结构的细致拆解2.1 原始文件结构和常见的目录布局解压后第一件事不要急着写代码先花十几分钟把目录结构和文件内容摸清楚。因为评测数据的组织方式和你在论文里看到的数据概览往往有出入而这些细节直接影响后续的预处理代码怎么写。当时我解压后看到的目录大致长这样ccksyidu4k-ner/ ├── train/ │ ├── 001.txt │ ├── 002.txt │ └── ... ├── test/ │ ├── 001.txt │ └── ... └── 标签说明.md (或 readme.txt)注意不同渠道流传的版本可能在文件组织上稍有差异有的直接把训练集和测试集放在同一目录下有的额外提供了dev.txt格式的验证集。核心原则是先看readme再看前几个文件的内容确认是原文格式还是BIO/BIOES标注格式再做预处理设计。这个数据集的标注粒度是字符级别的。每一行通常是一个字符及其对应的标签字符和标签之间用空格或制表符分隔。比如出 O 院 O 诊 O 断 B-疾病 O 冠 B-疾病 心 I-疾病 病 E-疾病这类格式和通用NER任务的标准输入基本一致好处是可以直接从HuggingFace的Tokenizer和各类NER工具链入手不需要自己做特别的格式适配。但也正因为格式太标准很多人反而忽略了文本内容的特殊性。2.2 实体类别体系5类实体和它们的临床含义CCKS2019医渡云任务定义的实体类别在评测指南里一般会给出明确说明。常见版本包含这几类实体类型含义典型例子身体部位人体解剖学部位肺部、左心室、股骨症状患者主观感受到的不适咳嗽、胸痛、乏力疾病已明确诊断的疾病名冠心病、肺炎、糖尿病检查实验室检查和影像学检查血常规、CT、心电图治疗药物、手术等治疗手段阿司匹林、冠脉搭桥术这5类实体基本覆盖了病历文本中最重要的信息维度。做临床应用时症状和疾病的区分很重要——症状是患者主诉层面的描述疾病是医生诊断层面的结论两者在文本中常常混在一起比如发热待查里的发热是症状肺炎是疾病。很多初学模型在这个边界上容易混淆后面我会专门讲怎么优化。另外值得注意的是治疗这个类别跨度很大既有药品名阿莫西林、又有手术操作名经皮冠状动脉介入治疗、还有一般治疗手段吸氧、补液这种上位类目合并会增加模型的学习难度但在实际评测中它算作一类不需要细分。2.3 数据规模和文本形态的直观感受我简单统计了一下当时的训练数据这里可以给大家一个大概的数量级参考具体数字以你下载的版本为准训练样本量约4000份文档所以叫4k每条文本长度从几十字到上千字不等常见的是200-500字标签类别总数5类实体 × B/I/E/S的前缀组合加上O标签大约16-17种如果你用BIOES文本形态上真实病历和教科书式的段落完全不同。举一个我记忆很深的例子一份出院记录的开头可能是这样的患者男性67岁因间断胸闷、气短10年加重伴双下肢水肿3天入院。这句话看着正常但拆开看信息密度极高胸闷气短双下肢水肿全是症状10年3天是病程时间加重是程度描述而这些碎片在标注时分布在不同的实体类型里。实际病历中还有大量查体T 36.5℃P 88次/分这类极其简洁的条目以及专科情况……这种半结构化文本。模型需要学会在自由文本和半结构文本之间切换识别策略这是与通用领域一个很大的区别。把数据格式摸清之后预处理的方向就明确了字符级标注、5类实体、BIOES标签策略、原始文本可能包含特殊符号和全半角混用这些都是后续代码里必须处理的点。3. 数据预处理与训练/验证集划分哪些坑我替你踩过了3.1 字符清洗与全半角统一一个小细节引发大问题拿到原始文本之后我建议做的第一件事不是直接进模型而是做一次彻底的文本画像统计字符分布、特殊符号、空格、空行、重复标点。这一步看似基础但直接影响后面BERT的输入质量和标签对齐。我当时遇到的一个实际问题是全半角符号混用。病历文本里有大量中文标点和英文标点混在一起的情况比如和(同时出现。和.也混用。如果直接把原始文本丢给BERT的分词器倒也不会崩溃但经过BERT自带的分词处理后某些符号会被拆开或归一化导致标签序列和token序列的长度对不上后续计算loss时可能出现offset错位。所以我在预处理里加了一步强制转换将全角字母数字转换为半角、将半角标点转换为全角中文语境下标点统一为全角更舒服。具体可以使用ftfy库或者自己写映射表核心是保证一个原始字符对应一个BERT token或明确的subword拆分关系。除了全半角还有两个隐藏问题一个是空格的处理病历中经常出现半角空格作为排版分隔如果不做处理BERT tokenize后可能输出空token导致对齐出错另一个是I-开头的标签不能出现在没有B-开头实体之后BIOES约束这些都需要在预处理阶段用规则检查一遍。3.2 训练集和验证集的划分策略不能简单随机很多初做NER的人喜欢直接把训练数据按8:2随机切分这在通用语料上通常问题不大但临床文本有很强的文档内一致性同一份病历里的症状、疾病、药物往往是互相呼应的如果同一份病历的句子被切到训练集和验证集两边验证集评估时会沾光导致F1虚高。我当时采用的方案是按文档编号划分而不是按句子或字符划分。先对文档做分层抽样确保不同实体类型在训练集和验证集中的分布比例大致一致然后再进入样本生成阶段。做法很简单import random from collections import Counter # 先统计每个文档中各类实体的数量比例用于分层抽样 def doc_entity_stats(doc_path): stats Counter() current_entity None with open(doc_path, encodingutf-8) as f: for line in f: line line.strip() if not line: continue char, label line.split() if label.startswith(B-): current_entity label[2:] stats[current_entity] 1 elif label.startswith(I-) and current_entity: stats[current_entity] 1 elif label O: current_entity None return stats # 按文档编号分层抽样 doc_ids list(range(1, 4001)) random.shuffle(doc_ids) val_count int(len(doc_ids) * 0.2) val_ids set(doc_ids[:val_count])这里的关键点在于不要用train_test_split直接切样本行因为这样会把同一份病历的上下文打断而且实体在切分边界处会被拦腰截断。按文档划分后再对验证集做一次句子完整性检查确保没有某个实体被截成半截。3.3 长文本截断策略简单截断会丢掉大量病历尾部信息BERT类模型的输入长度上限一般是512 Token而一份完整病历往往超过这个长度。最简单的做法是直接截断前512个Token但这样做会带来一个系统性的bias病历中出院医嘱和复查建议这类信息通常出现在文本末尾直接截断会导致模型完全看不到这些内容在测试集上遇到只含末尾信息的文本时表现会异常差。我建议采用滑窗切分重叠的方式。基本思路是把超长文档切成多个窗口每个窗口约为450个字符留出余量给BERT的special token相邻窗口之间保留50-100字符的重叠避免实体被切分到两个窗口的边界处。滑窗切分时有一个细节窗口切分的位置最好落在句号、换行等标点处而不是硬切。如果你按硬编码的450字符一刀切下去落在中间的是一个完整的药物实体名那这个实体就被破坏成两截标签也就废了。我当时写了一个简单的最近断点回退函数在预设断点附近找最后一个句号或分号把切分点回退到那里能显著减少边界bug。4. 模型选型与训练细节从BERTSoftmax到BERTCRF再到领域预训练4.1 基准模型BERTSoftmax为什么不够用中文NER目前的主流baseline基本都是预训练语言模型序列标注头。最初我把BERTSoftmax跑了一个版本验证集F1大概在86左右看似不错但细看bad case就会发现一个典型问题预测标签序列不合法。比如B-疾病- I-症状这种序列在Softmax输出下每个token独立取概率最大的标签模型完全不知道B后面应该跟同类型的I这个约束一旦出现这种错误实体边界就完全错了。解决这个问题有两个选择第一个是加CRF层让模型在解码时考虑标签间的转移约束第二个是用全局指针global pointer这类基于span的方案。对于这个数据集的规模CRF是性价比最高的选择。BERTCRF的原理不复杂BERT每个位置输出一个发射分数emission scoreCRF层学习标签之间的转移分数transition score解码时用维特比算法找到全局最优标签序列。它最大的收益不是提高单点准确率而是把标签序列必须合法这一先验知识硬编码进解码过程。HuggingFace生态里transformers库配合pytorch-crf或者torchcrf都可以很方便地实现。核心代码如下from transformers import BertModel, BertPreTrainedModel from torchcrf import CRF import torch.nn as nn class BertCRF(BertPreTrainedModel): def __init__(self, config, num_labels): super().__init__(config) self.bert BertModel(config) self.dropout nn.Dropout(config.hidden_dropout_prob) self.classifier nn.Linear(config.hidden_size, num_labels) self.crf CRF(num_labels, batch_firstTrue) self.init_weights() def forward(self, input_ids, attention_mask, labelsNone): outputs self.bert(input_ids, attention_maskattention_mask) sequence_output outputs[0] sequence_output self.dropout(sequence_output) logits self.classifier(sequence_output) if labels is not None: loss -self.crf(logits, labels, maskattention_mask.bool()) return loss else: decoded self.crf.decode(logits, maskattention_mask.bool()) return decoded注意torchcrf的CRF层要求batch_firstTrue并且mask必须传attention_mask的布尔值我自己第一次跑就忘了转bool折腾了半天报错才发现是dtype的问题。4.2 标签策略BIO还是BIOES对连续实体影响很大中文NER里标签策略的选择经常被忽略。BIOB-beginI-insideO-outside是最常用的但BIOES额外加入E-end和S-single对实体边界的学习更有利尤其是在实体内部出现连续子词或嵌套可能时。病历文本里有一个特点很多实体是并列结构比如肝、肾功能检查肝和肾分别独立后面接一个功能检查。如果用BIO标签模型有可能把肾功能检查识别为一个实体但实际上标注规则要求肾功能检查是检查类实体而肝因为缺少功能二字可能单独被标为身体部位或直接被忽略。这种边界问题用BIOES会好很多因为S标签可以明确表达单个字就是一个完整实体。我当时对比了BIO和BIOES在验证集上的效果BIOES大约能给F1带来0.5-1个百分点的提升尤其在身体部位和症状这两个类别上。代价是需要多写几行转换代码非常划算。4.3 超参数与训练策略一轮全量微调还是两阶段冷启动BERTCRF微调时有几个超参数对结果影响显著学习率LRBERT层建议用较小的学习率2e-5到5e-5CRF层和线性层可以用稍大的学习率1e-4到2e-4可以通过optimizer.group_params分组实现。Batch size受显存限制我用了16在单张T4上刚好能跑。Epoch数3-5轮。这个数据集规模小2轮就能过拟合我观察3轮效果最好之后验证集开始掉点。Warmup ratio0.1训练初期避免剧烈震荡。Max length我之前滑窗设了450如果BERT需要加special token512以内都够。还有一个容易被忽视的问题类别不平衡。在这个数据集里O标签占比可能超过60%少数类如治疗的实体数量远少于症状。如果直接交叉熵损失模型会倾向于把所有token都预测为O。解决办法一般有两个一是给CRF的发射分数加类别权重但CRF的loss通常不支持直接加权二是在解码后做一个阈值调整只在某个实体类别的最大概率超过一定阈值时才接受该预测。更稳妥的做法是不调权重先跑一个纯baseline统计每个类别的F1然后针对落后类别做数据增强或规则修正。我在训练中采用的是一种两阶段思路第一阶段用通用BERT如bert-base-chinese做全量微调跑通整个流程得到一个baseline第二阶段再用领域预训练模型比如在中文医学语料上继续预训练的模型如bert-base-chinese-med或MC-BERT替换底座其他参数不动重新微调。两阶段能让我清楚地区分模型结构问题和预训练语料领域差异问题各自对结果的贡献。4.4 解码后处理规则修正与片段约束深度学习模型跑出来的原始预测一定会有一些低级错误在医疗场景下这些错误不可接受。比如左肺上叶被识别成左肺和上叶两个独立身体部位或者胸闷、气促中的顿号被错误包进症状实体里。对这类问题我加了解码后的规则修正层标点边界修正实体首尾不能是标点符号。若预测span以逗号、顿号、句号开头或结尾直接截断或丢弃。停用词过滤某些词如患者、入院不应作为实体主体若模型预测为疾病或症状则降级为O。长度约束单字符实体需要谨慎对待。如果模型预测了一个单字疾作为疾病实体大概率是误报可以设置最小实体长度阈值对大多数类别设为1但针对身体部位类可以允许单字因为临床上确实有肝肾这样的单字实体。这一层规则通常能提升F1约0.5个百分点更重要的是让预测结果在临床语境下看起来合理方便后续做结构化信息抽取。5. 评测指标的正确打开方式从官方F1到bad case分析5.1 精确匹配还是宽松匹配直接决定分数高低NER公认的评测指标是实体级别的精确率Precision、召回率Recall和F1。但什么算一个实体被正确预测在医学文本里很微妙。最严格的方案是实体边界和实体类别都完全匹配才算对这也是官方评测的标准。宽松一些的方案是只判断实体类别忽略边界或者只判断边界忽略类型医疗场景下这两种都是不可取的因为临床信息抽取中边界和类型同样重要。我用官方标准的严格匹配跑了baseline验证集F1大约在88-89之间具体数值取决于数据版本和随机种子。但别急着高兴这个分数在垂直领域里只能算能跑离可用还有距离。想要进一步突破必须回到bad case分析。5.2 细化到类别的错误分析症状vs疾病是重灾区我通常会把预测结果按实体类别拆开逐类统计P/R/F1并抽取每个类别的错误样例。当年跑完印象最深的三个错误模式第一症状和疾病相互混淆。文本里肺部感染可能被标为症状因为模型看到感染联想到发热但实际是疾病。反过来的情况也存在。要缓解这个问题可以在后处理时维护一个常见疾病词表和常见症状词表当模型输出的实体在两个词表中都有出现时优先选择词表投票多的那个。第二检查和治疗的边界不清。比如行心电图检查中心电图是检查行冠脉造影术中冠脉造影术虽然也是检查操作但有些版本的标注规则把它归入治疗容易导致误判。这种问题没有银弹唯一有效的方式是仔细研读评测指南中的实体定义必要时结合少量人工标注做标注一致性校验。第三长实体的中间片段被截断。比如冠状动脉粥样硬化性心脏病是一个完整的疾病实体模型有时只识别出冠状动脉粥样硬化或心脏病漏掉了性。这类问题可以通过CRF的转移约束缓解部分但真正有效的办法是增大训练数据中长实体比例或者使用基于span的方案如GlobalPointer直接预测实体的起止位置。5.3 误差来源归类到底是模型问题、数据问题还是标注问题做bad case分析时我习惯把错误分成三类模型自身局限比如长距离依赖捕获不足、少见实体泛化差。这类错误可以通过增大模型容量、添加外部知识、引入实体词典来缓解。数据噪声训练集里出现标注不一致的情况比如同一份方案中肺部CT有时标为检查有时标为身体部位检查的组合导致模型无所适从。这类错误需要回头整理数据。标注规范歧义有些边界的确定本身就有主观性。比如血压升高中的升高算不算症状的一部分不同标注员的尺度不同。这类问题只能靠统一标注规范来消化模型层面能做的有限。把bad case按照这三类归档之后再去选择优化方向就很有针对性了。很多人一上来就换模型、调参效果却不理想原因就是没有先把错误归类。6. 精度进阶之路从baseline到更高F1的几个有效手段6.1 领域预训练模型换个底座带来的收益比想象中更明显在基线模型跑通的基础上我把底座从bert-base-chinese换成了在医学语料上继续预训练的模型。这里有一个常见的误区不是随便找一个医学BERT就无脑用要关注它的预训练语料是否包含电子病历、是否包含你目标领域的实体类型。有些医学BERT是用医学教材和百科训练的风格偏向书面语与病历文本的差距依然很大。我实际测试过三种底座底座验证集F1约说明bert-base-chinese88.2通用最强baseline医学百科预训练BERT89.4提升明显但病历口语化表达仍受限电子病历语料继续预训练BERT90.3最贴近目标场景提升最大这里不写具体模型名因为可用的开源模型版本一直在变大家在自己跑的时候最好多试几个观察验证集的表现。原则是预训练数据与目标领域越接近微调后的效果上限越高。6.2 对抗训练FGM/PGD小数据集上的免费午餐垂直领域数据集规模小模型极易过拟合。对抗训练是通过在输入Embedding上添加微小扰动让模型对输入的小变化保持鲁棒性这在小数据集上通常能带来稳定的F1提升。以FGMFast Gradient Method为例实现非常简单class FGM: def __init__(self, model, epsilon0.5): self.model model self.epsilon epsilon self.backup {} def attack(self): for name, param in self.model.named_parameters(): if param.requires_grad and param.grad is not None: self.backup[name] param.data.clone() r_at self.epsilon * param.grad / (param.grad.norm() 1e-12) param.data.add_(r_at) def restore(self): for name, param in self.model.named_parameters(): if name in self.backup: param.data self.backup[name] self.backup.clear()训练时每个batch先正常计算loss和梯度然后调用attack()用带扰动的Embedding再算一次loss累加梯度后更新参数最后restore()恢复原始Embedding。这个技巧通常能给F1带来0.3-0.8个百分点的提升几乎没有额外推理成本。小数据集上强烈推荐。6.3 实体词典匹配与远程监督把规则注入模型除了纯模型优化我还尝试了实体词典远程监督的方式构建一个覆盖常见疾病、药品、检查项目、身体部位的词典用词典对训练文本做自动标注得到伪标签拼接到训练数据中。这需要谨慎操作因为词典匹配会产生大量边界噪声反而干扰模型学习。我最终采用的方法是只对词典中置信度高的实体类别如常见药品名做匹配并且对伪标签对应的样本设置较低的loss权重相当于一种软引导。实测下来这种做法对药品和检查实体类别的召回率提升比较明显但会轻微损伤Precision整体F1有小幅净收益。如果追求上线鲁棒性我建议宁可牺牲一点F1也要保证Precision医学场景宁可不识别也不能乱识别。6.4 集成与投票不要迷信单模型多个seed的投票也能涨点单模型多次训练的结果存在随机性。我当时训练了3个不同随机种子的BERTCRF模型在推理阶段对输出序列做投票或直接对预测实体的起止和类型做多数表决F1又涨了0.5左右。集成不会让模型发生质变但在比赛或需要稳定结果的场合这个方法简单有效。需要注意的是不同seed的模型在验证集上性能差异可能达到0.5-1个百分点所以必须统一评测标准、统一阈值否则投票结果可能被某个较差模型拖累。7. 踩坑实录几个卡住我一整天的莫名其妙7.1 CRF的mask和input_ids长度不一致这是我最开始调BERTCRF时遇到的第一道坎。用了DataCollatorForTokenClassification后它对labels做了paddingpadding的位置label值通常是-100而CRF层要求label中的padding位置不能参与计算。但如果你用的是torchcrf它没有自动跳过-100的能力你必须把attention_mask布尔型同时传给CRF的decode和loss计算。第一次跑我把attention_mask原样传进去int型结果CRF报类型错误。把mask转成bool之后又开始出现loss为nan的情况。排查后发现是Embdedding的padding部分没有完全mask掉导致CRF在padding位置计算了无意义的转移分数。解决方案是在模型forward里把attention_mask.bool()显式传入CRF并确保label的padding位置同样与mask对齐。7.2 全角空格导致Tokenizer输出空token标签完全错位有一个batch的loss突然变大模型预测结果一片混乱。检查后发现那条文本中间有一个类似 的全角空格BERT tokenizer把它当成了一个token但我的标签序列里根本没有给它分配位置导致后续所有token的标签全部错位一个位置。滑窗切分时这个问题尤其隐蔽因为肉眼很难发现全角空格的存在。解决办法是在预处理阶段统一把所有空格字符包括全角空格替换为半角空格再进一步决定是保留还是删除。7.3 滑窗切分把多字实体劈成两半即使加了最近断点回退仍然会出现某个窗口结尾处落下半个实体的情况。一个典型的例子是冠状动脉支架植入术如果窗口在支架中间断开第二个窗口的架植入术在预测时极可能产生一个残缺的治疗实体。我后来加了一个实体完整性保护逻辑在切分时如果发现窗口末尾几个字符匹配到已知实体词表的前缀重叠一部分就把窗口向外扩展几个字符直到实体完整。这个方案虽然会让切分长度略有变化但能明显减少边界断裂问题。7.4 验证集效果不错测试集却崩了隐藏的实体分布漂移训练和测试数据虽然来自同一个任务但两组文本的实体分布存在差异。比如训练集中症状类实体占比最高但测试集中检查类实体的比例明显升高导致基于训练集调优的阈值和词典权重在测试集上不适应。这几乎是所有NLP竞赛的常态。我的应对是做模型选择时不要只盯着验证集整体F1还要看各类别F1的方差。如果某个类别在验证集上偏低就要警惕它在测试集上可能更低优先针对性优化。8. 我最后想说的几点实在话这篇东西写到这里该讲的技术点基本讲完了。最后说几点个人体会不算总结只是踩过坑之后觉得值得提醒后来人的东西。第一拿到这类医学文本数据花时间读数据比急着跑模型重要得多。我会建议你打开5-10份原始标注文件一个字一个字地读一遍弄清楚实体边界在哪里切分、并列结构怎么处理、不同医生书写风格对标注的影响。这个过程虽然枯燥但它能让你对数据产生一种手感后续做规则修正和bad case分析时这种手感就是你的直觉来源。第二不要小看规则修正层的价值。深度学习模型在垂直领域里的稳定输出几乎永远是模型规则协同的结果。医学场景尤其如此因为它对错误的容忍度极低。规则不是退步它是对模型的兜底。第三如果你想把这个数据集作为自己医疗NLP研究的起点建议在此基础上继续扩展把5类实体映射到更细粒度的临床本体如UMLS、SNOMED CT把命名实体识别扩展为实体链接和关系抽取把单文本处理扩展到多文档病历融合。CCKS2019医渡云4k数据集本身只是入场券真正的价值在于你通过它熟悉的那些医疗文本处理能力可以在后续很多任务中复用。如果你也在跑这个数据集或者在做其他中文医疗NER项目欢迎在评论区交流你遇见的bad case特别是模型在症状vs疾病边界上的表现我很想知道大家都有什么解法。本文还有配套的精品资源点击获取
返回列表