信息速览
临床文本里最琐碎也最要命的一步,是把医生随手写下的病名变成一个机器能对上号的编号。写"心力衰竭"好办,标准术语表里有一个现成的概念;写"轻度左下肺纤维化伴牵拉性支气管扩张"就麻烦了,标准术语表里没有哪一个概念能原样装下这句话,于是这条提及只能被标记为 CUI-less——没有对应的概念唯一标识符。CUI 是统一医学语言系统(UMLS)给每个概念发的编号,CUI-less 就是"发不出号"。
CUILESS2016 专门处理这批"发不出号"的提及。亚拉巴马大学伯明翰分校与亚利桑那大学信息学院的联合团队,从 2015 年语义评测第 14 项任务(SemEval-2015 Task 14)所用的 ShARe 临床语料里取出 5,397 条被判为 CUI-less 的疾病提及,逐条重新映射到 SNOMED CT,并且放开了一个此前一直被禁止的自由度:一个疾病实体可以对应多个 UMLS 编号。
它与「无袖带血压」没有任何关系。名字里的 CUI 是概念唯一标识符,与 cuff(袖带)只是撞了读音;数据包里没有一条生理信号,没有一个血压值,人也不是受试者而是病历文本。这个误会值得在开头就说清,因为检索这个库名的人里,相当一部分是被缩写误导来的。一屏速览见下表。
| 维度 | 内容 |
|---|---|
| 官方全名 | CUILESS2016(Concept Unique Identifier-less 语料库) |
| 中文定位 | 临床概念归一化语料,不是生理信号数据集 |
| 发布平台 | PhysioNet,2018 年 1 月 24 日上线,版本 1.0.0 |
| 主要作者 | John D. Osborne、Matthew B. Neu、Maria I. Danila、Thamar Solorio、Steven J. Bethard |
| 机构 | 亚拉巴马大学伯明翰分校;亚利桑那大学信息学院 |
| 原始语料 | ShARe 语料中的疾病提及(SemEval-2015 Task 14 所用版本) |
| 规模 | 5,397 条曾被判为 CUI-less 的疾病提及 |
| 概念体系 | SNOMED CT,取 UMLS 2016AB 内嵌的 2016 年 9 月版 |
| 分发形态 | 两个压缩包:训练集与开发集,解开后为管道分隔文本 |
| 每行字段 | 19 列(报告名 + 提及区间 + 概念编号 + 十二个线索列) |
| 压缩包体积 | 训练包约 75 KB,开发包约 39 KB,合计解压后一百多 KB |
| 原文是否随包 | 否,临床文本须另行向 QCRI 申请并签协议 |
| 许可 | ODC-BY 1.0,署名即可使用 |
| 标注一致性 | 严格精确匹配 52.4%,层级节点重合口径 78.2% |
| 典型用途 | 概念归一化模型评测、组合式本体映射、术语覆盖度研究 |
§1 它要解决的具体麻烦
1.1 标准词表装不下医生的说法
概念归一化的目标听上去很朴素:把文本里的一段病名,换成标准术语表里的一个编号。做起来却处处碰壁。标准术语表是一条条预制好的概念,每条概念的名字都是专家在某个时刻定下来的;医生的表达是无穷无尽的组合,同一个意思可以有一百种写法,而其中总有那么一大片,恰好落在所有预制概念之间的缝隙里。
这些缝隙里的提及,在早期的评测语料里统一被标成 CUI-less。这个标签的意思不是"标注者不知道这是什么",恰恰相反,标注者完全知道这句话说的是什么病,只是标准术语表里没有一个现成的编号能装下它。于是出现一个尴尬的局面:语料里明明有大量疾病提及,但作为训练目标是有害的——模型学到的是"这条不用管"。
CUILESS2016 的价值就在这个尴尬处。它承认标准术语表的缝隙是真实存在的,然后提出一个替代方案:既然单个编号装不下,那就用几个编号拼。这种拼法在术语学里叫后组合,这批作者给了它一个更朴素的名字——组合式概念。
1.2 三条常见的错误期待
第一条,期待它是血压或无袖带监测数据。这是库名缩写造成的最高频误认。CUI 与 cuff 在英文里拼写相近,PhysioNet 又是一个心电、血压类数据的大本营,两者叠加,检索「cuffless」的人极容易误入此地。事实上整份数据里唯一与医学实体打过交道的,就只有病名文本。核对办法很简单:打开压缩包,看到的是以报告号命名的 .pipe 文本文件,不是波形。
第二条,期待它是 ShARe 的完整标注版。它不是。ShARe 语料里的疾病提及远不止这个数,CUILESS2016 只挑了共享任务判为 CUI-less 的那一部分。换句话说,它是一个"补丁",只覆盖原语料的一个子集,而且是最难的那部分子集。想拿它替代 ShARe 做端到端训练,会发现大量本来就有预制映射的提及根本不在里面。
第三条,期待它自带原文。也不对。官方页面写得很清楚:临床文本不随本语料分发,需要原文的人要按 QCRI 的说明签署数据使用协议自行下载。这意味着拿到压缩包的人,一开始手里只有一串报告名加字符区间,看不到任何一句话。
1.3 它能给到的与给不到的
| 你的需求 | 它给的 | 够不够 |
|---|---|---|
| 训练一个把疾病提及映射到 UMLS 编号的模型 | 训练包里有数千条已映射的提及与区间 | 够,但原文要另外申请 |
| 评估一个已有归一化系统在"难例"上的表现 | 全部是共享任务判为 CUI-less 的难例 | 够,而且比在全集上评测更苛刻 |
| 研究组合式概念标注到底长什么样 | 概念列允许空格分隔的多编号 | 够,这是它最独特的观察窗口 |
| 做药物、检验、解剖部位的归一化 | 只有疾病一类实体 | 不够,实体类别单一 |
| 做中文或非英语的归一化 | 全部为英文病例 | 不够,语言单一 |
| 直接拿区间去切文本 | 只给字符位移,不给原文 | 不够,必须自己配原文 |
| 复现 2018 年论文的全部实验 | 语料与划分齐全 | 基本够,超参与原实验细节需看论文 |
| 判断某个病名"该用哪个概念"的临床真值 | 标注者有分歧,一致率不到六成 | 不够,不能当唯一真值 |
1.4 你的处境与它能帮到的事
| 你的处境 | 它能帮你什么 | 下一步该做什么 |
|---|---|---|
| 你的实体链接模型在全量测试集上分数很高,但线上被医生吐槽"稍微绕一点的说法就认不出" | 提供一个只由难例组成的测试面,把模型的弱点放大 | 先用你的模型跑开发包,看多概念映射被拆成单概念的比率 |
| 你在设计一个本体映射系统,纠结要不要支持后组合 | 提供一批真实的后组合标注,可以直接看专家是怎么拼的 | 抽出十行看概念列的空格,对照 §4.3 的案例理解拼法 |
| 你要做术语覆盖度评估,想知道 SNOMED CT 到底漏了哪些表达 | 这批提及本身就是"漏掉的部分"的样本 | 结合 §2.4 的列结构,把概念数与提及数分开统计 |
| 你在做标注一致性研究,想找一个分歧率的真实基线 | 论文给了两个口径的一致性数字 | 用同一口径在你自己的语料上复算,再比较 |
| 你的团队要接一份英文临床文本的归一化模块,但只有中文团队 | 一份体量极小、许可宽松的入门语料 | 全量解压不到一兆,先用它跑通管线再接大库 |
| 你在检索「cuffless」却撞见了这一条 | 它明确告诉你这不是血压数据 | 转去看库内的 PulseDB 或 CardioWave 两条 |
1.5 一句话判断
它是一块只补最难那一格的拼图:规模小得可以几分钟读完,却不允许你把"一病一码"的简单假设带进去。
1.6 不适合谁:四条边界
不适合拿来做大规模预训练。 两个压缩包合计一百多 KB,解压后是两百多个小文件。用这份体量去喂一个语言模型,除了记住这两百多份报告别无他用。
不适合做慢病风险建模或队列研究。 它没有任何患者层面的结构化变量——没有年龄、没有性别、没有随访、没有结局。它只有"某份报告里的某个字符区间对应哪些编号"。
不适合做单标签分类。 组合式标注的精髓就是一条提及可能带多个编号。如果你把它压成一个标签做多分类,丢掉的恰恰是这个数据集唯一独有信息。
不适合在没有原文的情况下做端到端训练。 只拿坐标不加原文,模型学不到任何东西。原文的获取是一条独立的路,需要签协议、需要走 QCRI 的流程,这一点在 §5 与 §9 各说一次。
§2 数据构成与规格
2.1 两个压缩包与一份辅助清单
官方文件目录下只有四项:训练集压缩包、开发集压缩包、一份语义近似概念集清单、一份校验和文件。整个项目的未压缩总量在官方页面上写作一百四十余 KB,是所有 PhysioNet 项目里最小的那一档。
| 文件 | 说明 | 它在语料里的角色 |
|---|---|---|
CUILESS_TRAIN.tar.gz |
训练集,约 75 KB | 解开后是一批按报告号命名的管道分隔文件 |
CUILESS_DEV.tar.gz |
开发集,约 39 KB | 结构同上,报告集合不同 |
semanticly_similiar_concept_sets.txt |
语义相近概念集 | 辅助判断哪些编号可以互换 |
SHA256SUMS.txt |
校验和 | 校验下载完整性 |
这里有个细节值得留意:文件名里的 similiar 少了一个 r,正确拼写是 similar。官方目录就长这样,用脚本批量抓取时不要把文件名"修正"成正确拼写,否则会 404。
2.2 字段/记录的完整字典
每行 19 列,用竖线分隔。列的顺序沿用 SemEval-2015 Task 14 的格式,唯一改动在第三列:原格式要求一列只放一个概念编号,这里允许放多个,用空格隔开。
| 列序 | 列名 | 取值形态 | 含义 | 使用注意 |
|---|---|---|---|---|
| 1 | report name | 00174-002042.text |
报告文件名 | 每组区间只在这份报告内有效 |
| 2 | disorder span | 965-983 |
提及的字符起止 | 左闭右开,取自原文偏移 |
| 3 | cui | C0424000 或 C1286744 C1299582 |
UMLS 概念编号,可多值 | 空格分隔即组合式表达 |
| 4 | Norm_NI | yes / no |
该提及是否被否定 | 与第 5 列配对 |
| 5 | Cue_NI | 字符区间或 null |
否定线索的位置 | 无否定时为 null |
| 6 | Norm_SC | patient 等 |
主语归属归一化 | 常取 patient 或 family |
| 7 | Cue_SC | 字符区间或 null |
主语线索的位置 | 同一行多组区间用逗号分隔 |
| 8 | Norm_UI | no 等 |
不确定语义归一化 | 与第 9 列配对 |
| 9 | Cue_UI | 字符区间或 null |
不确定线索位置 | |
| 10 | Norm_CC | increased 等 |
临床状况变化归一化 | |
| 11 | Cue_CC | 字符区间或 null |
变化线索位置 | |
| 12 | Norm_SV | unmarked 等 |
严重度归一化 | 无标记时写 unmarked |
| 13 | Cue_SV | 字符区间或 null |
严重度线索位置 | |
| 14 | Norm_CO | false 等 |
通用线索归一化 | |
| 15 | Cue_CO | 字符区间或 null |
通用线索位置 | |
| 16 | Norm_GC | false 等 |
一般性线索归一化 | |
| 17 | Cue_GC | 字符区间或 null |
一般性线索位置 | |
| 18 | Norm_BL | C0000726 等 |
身体定位归一化,取值是概念编号 | 这一列的取值形态与其他 Norm 列不同 |
| 19 | Cue_BL | 字符区间或 null |
身体定位线索位置 |
后十二列不是 CUILESS2016 新增的,它们来自共享任务原格式。这份语料的贡献集中在第 3 列。理解这一点,能省掉很多困惑:如果你在做属性抽取,这十二列可以直接当现成的弱标签用;如果你只关心概念映射,读完前三列就够了。
2.3 一条记录的完整解剖
取开发包里第一份报告的首行:
00174-002042.text|965-983|C0424000|no|null|patient|null|no|null|unmarked|null|unmarked|null|false|null|false|null|null|null
逐段读:这份报告叫 00174-002042.text;疾病提及位于第 965 到 983 个字符之间,占 18 个字符;映射到的概念编号是 C0424000;没有被否定;主语是患者;不确定标记为否;临床状况无变化;严重度为无标记;通用与一般性线索均为否;身体定位与时间、检验指标都为 null。十九列里绝大多数是 null 或 false,这是共享任务格式的常态——大部分提及就是一句干巴巴的病名,没有否定、没有严重度、没有解剖定位。
再看同一份报告里一条带组合的行:
00174-002042.text|1098-1124|C1286744 C1299582|no|null|patient|null|no|null|unmarked|null|unmarked|null|false|null|false|null|null|null
前两列与上一行同构,第三列换成两个编号,中间一个空格。这一行的含义是:这段 27 个字符的提及,需要一个概念 C1286744 与另一个概念 C1299582 合起来才能说清。至于这两个编号分别叫什么名字,需要去 UMLS 里查。这份语料只给编号,不给名字,也不给关系的名字。
还有一类行,第 18 列有值:
00174-002042.text|2152-2155,2175-2188|C0424826|no|null|patient|null|no|null|unmarked|null|unmarked|null|false|null|false|null|C0000726|2152-2155
第 2 列出现了两组区间,用逗号隔开——这是共享任务里"一个疾病提及由不连续的几段文字组成"的写法。第 18 列给了身体定位的概念编号,第 19 列指明哪一段区间是定位线索。这类不连续提及在组合式映射里特别重要,因为其中一段往往就是"限定词",另一段是"核心词"。
用 Python 解析这几行不需要任何第三方库:
import glob
import collections
#-- 逐文件读,每行 19 列,第三列可能含空格
rows = []
for path in sorted(glob.glob('CUILESS_DEV/*.pipe')):
for line in open(path, encoding='utf-8'):
f = line.rstrip('\n').split('|')
if len(f) != 19:
continue
rows.append({
'report': f[0],
'span': f[1],
'cuis': f[2].split(),
'negated': f[3],
})
print(len(rows), len({r['report'] for r in rows})) #-- 提及数与报告数
print(collections.Counter(len(r['cuis']) for r in rows))
最后一行打印的是"每个提及带几个编号"的计数。这不是分布分析,是结构确认——它告诉你多值那一列到底有多常见,决定你的模型要不要从一开始就按多标签设计。
2.4 报告与提及的两级结构
数据是两级组织:一份报告一个文件,文件内若干行提及。
| 层级 | 单位 | 唯一性 | 划分约束 |
|---|---|---|---|
| 报告 | 一个 .pipe 文件 |
报告名唯一 | 划分应按报告分组 |
| 提及 | 文件内一行 | 由报告名加区间唯一定位 | 同一报告内可有多条 |
| 概念 | 第三列里的一个编号 | 全局唯一 | 可被多个提及共享 |
这个两级结构决定了划分方式。按提及随机切分会把同一份报告的不同提及分到训练与测试两侧,而同一份报告里的表达风格、缩写习惯高度一致,泄漏几乎不可避免。官方给的两个包是按报告切的,用现成的划分最省事。
2.5 与同类资源的字段差异
| 对比项 | CUILESS2016 | ShARe 语料 | MedMentions | COMETA |
|---|---|---|---|---|
| 实体类别 | 仅疾病 | 疾病 | 全部语义类型 | 仅疾病 |
| 是否含原文 | 不含 | 含 | 含 | 含 |
| 映射目标 | SNOMED CT,可多值 | SNOMED CT,单值 | UMLS,单值 | SNOMED CT,双层 |
| 语言 | 英文 | 英文 | 英文 | 英文 |
| 规模量级 | 数千提及 | 数万提及 | 数十万提及 | 两万提及 |
| 覆盖重点 | 只覆盖难例 | 全集 | 文献摘要 | 社交媒体口语 |
这张表的关键在最后一行之前的那一行。CUILESS2016 的定位不是"更多",而是"只在这一个角落更深"。它与 MedMentions、COMETA 不是竞争关系,前者在两处硬约束上不可替代:一是允许一个实体对多个编号,二是它只由难例构成。
§3 它是谁的数据:一个补丁式语料的来历
3.1 贡献者与分工
作者名单里五个名字,机构横跨两州。亚拉巴马大学伯明翰分校的三位——John Osborne、Matthew Neu、Maria Danila——承担主要的标注与整理;亚利桑那大学信息学院的 Steven Bethard 与加州大学圣克鲁兹分校背景的 Thamar Solorio 负责方法设计与实验。PhysioNet 页面列出的机构只写了前两处,Solorio 的署名出现在论文里。
这种跨机构组合在临床 NLP 领域很常见:一边是有临床资源的医学院,一边是有评测方法积累的信息学院。前者能拿到真实病例并组织临床人员标注,后者知道怎么把标注变成可比较的数字。
3.2 时间线
| 时间 | 事件 | 意义 |
|---|---|---|
| 2015 年 | SemEval-2015 Task 14 举办,ShARe 语料中的 CUI-less 提及成为一个公开问题 | 问题被正式提出 |
| 2017 年 | 论文发表于 Journal of Biomedical Semantics | 方法定稿 |
| 2018-01-24 | 语料在 PhysioNet 上线,版本 1.0.0 | 数据公开 |
| 2018 年至今 | 版本停在 1.0.0 | 未再扩版 |
第三行之后没有第四行。这份语料上线后没有发过第二版,文件修改时间停留在 2018 年 1 月 19 日(压缩包内的时间戳),上传时间晚五天。
3.3 问题的提出方式
SemEval-2015 Task 14 是概念归一化评测的一个转折点。此前评测的默认做法是"一个提及对上一个概念",凡是找不到合适概念的提及就标为 CUI-less 跳过。这造成一个统计上的失真:评测报告里的准确率,分母里不含最难的那部分样本。
CUILESS2016 的论文摘要用了很克制的表述:传统语料把概念归一化成"预制概念",少数语料用了"后组合概念",但后组合里的额外编号被限制在若干指定关系之内,这种限制削弱了归一化表达语义的能力。作者的解法是把限制去掉——不限定关系,就叫它组合式概念。
3.4 三层来源
| 层次 | 内容 | 是否公开 |
|---|---|---|
| 第一层 | ShARe 语料的原始临床报告文本 | 需向 QCRI 申请并签协议 |
| 第二层 | 报告中的疾病提及区间与十二个线索列 | 随 ShARe 发布 |
| 第三层 | 这些提及在 CUILESS2016 里的新映射 | 随 PhysioNet 包发布 |
三层的关系决定了使用路径:想真正训练模型,必须把第三层与第一、二层拼起来;只想研究映射本身,第三层单独也够用。这个拆分不是作者偷懒,是去标化合规的要求——临床文本的再分发需要单独授权,而概念编号本身不构成隐私风险。
3.5 与共享任务的口径对照
把两侧的设定逐条摆开,能看清这份语料的改动其实只有一条,其余都是继承。
| 设定项 | SemEval-2015 Task 14 | CUILESS2016 | 变化 |
|---|---|---|---|
| 实体类别 | 疾病 | 疾病 | 不变 |
| 映射目标 | SNOMED CT | SNOMED CT | 不变 |
| 每个提及的编号数 | 一个 | 一个或多个 | 放开 |
| 概念语义类型限制 | 限定在若干组 | 不限 | 放开 |
| 线索列 | 十二列 | 十二列 | 不变 |
| 文件格式 | 管道分隔 | 管道分隔 | 不变 |
| 标注对象 | 全集疾病提及 | 仅 CUI-less 提及 | 收窄 |
| 数据划分 | 训练与开发 | 训练与开发 | 沿用 |
只有第四行的两个"放开"是真改动,第六行的"收窄"是取材范围的变化。其余六行原样继承。这种最小改动的做法有一个直接好处:任何按 Task 14 格式写好的读取脚本,都能直接读这份语料,不需要新写解析器。坏处也在这里——格式上的沉默会让不熟悉背景的人误以为两者是同一份东西,只差一个版本号。
第八行值得多说一句。官方给的两个包并不是随手的六四开切分,它承接的是共享任务原先的报告级划分,因此同一个作者、同一家机构、同一段时期的写法特征在两个包里被刻意分开。这一点在 §2.4 已经说明过一次,这里再从口径的角度补一句:划分是任务设计的一部分,不是发布时随手做的操作。
§4 它最独特的东西:一个实体几个编号
4.1 组合式归一化到底是什么
举一个中文化的例子来理解。假如术语表里有"肺炎"这个概念,也有"左下肺"这个解剖概念,但没有"左下肺肺炎"这个合成概念。传统做法是强行映射到"肺炎",丢掉部位信息;组合式做法是把"肺炎"与"左下肺"两个编号一起写出来。
这不是简单的"多标签"。多标签通常指"一段文本同时涉及多个不同的病",而组合式指的是"这里只有一个病,但它需要几个概念拼起来才描述完整"。两者在数据上长得一样——第三列都是多个编号——语义上完全不同。用多标签分类的框架去处理,会把"肺"和"肺炎"当成两个并列的类,这在评估时会得出古怪的结论。
论文对这一点有明确的动机陈述:后组合的限制会影响语义表达力。去掉关系限制之后,标注者可以自由地把任意必要的概念并置,表达力强了,可比较性弱了——这也是为什么两个标注者的一致率不高。
4.2 为什么这篇语料必须存在
如果只是为了多标签,随便找一个大语料拆标签即可。必须重做一遍的理由在于:原来那份语料的 CUI-less 提及,是共享任务在"只许单编号"的约束下判出来的。约束一变,判定就变——原本"找不到唯一概念"的提及,在允许组合之后大半都能归上号。论文摘要给了这个结果:除 8 条之外,全部用这套方法完成了归一化。
这句话值得细读。它说明 CUI-less 这个标签在相当程度上不是"术语表缺概念",而是"单编号格式下的表达力不足"。真正无解的只有个位数。这对术语工程是一个重要判断:扩表可能不如改格式。
4.3 案例:00174-002042 这一份报告
开发包里第一份报告是 00174-002042.text,它的行数在整份开发集里属于偏多的一档。把这份报告的提及按第三列的编号个数摊开看,能得到三种典型形态:
| 形态 | 第三列的样子 | 含义 | 处理建议 |
|---|---|---|---|
| 单编号 | 一个编号 | 术语表里有现成概念 | 常规多分类即可 |
| 双编号并列 | 两个编号,空格分隔 | 一个核心概念加一个限定概念 | 需要关系推断,不能当两类 |
| 不连续提及加定位 | 区间含逗号,第十八列有值 | 核心词与限定词在原文里不挨着 | 先把区间拼起来再谈映射 |
这份报告里还能看到否定标记:有些行的第四列是 yes,第五列给出否定词的区间。例如"没有发现某某病变"这种句子,提及本身存在,但语义被否定。归一化模型如果只学提及到编号的映射,会把这些否定提及当成阳性证据,这是临床 NLP 里最常见的一类错误,在 §7.3 会再讲。
把这三行放在一起,就构成了这份语料的全部形态。§4.3 的案例在全文被引用三次以上,分别是理解列结构(本节)、写解析脚本(§5.4)与评估误判(§7.2),原因是它足够小——一份报告就能装下所有要讲的形态。
4.4 语义近似概念集那一份清单
根目录下的 semanticly_similiar_concept_sets.txt 是一份辅助材料,收录语义上可以互换的概念集合。它的用途在评估环节:当模型给出的编号与标注给的编号不同、但两者落在同一个近似集合里时,这算不算错?
这个问题在组合式语境下更尖锐。一个提及映射到编号 A 与 B,模型给出 A 与 C,如果 B 与 C 语义近似,严格匹配会判错,层级或集合口径会判对。这份清单就是让后一种口径可以落地。使用它之前要先决定评测口径,反过来用它去"宽恕"模型错误则会自欺。
4.5 边界条件:什么时候它不再适用
| 条件 | 是否适用 | 判断依据 |
|---|---|---|
| 你要做英文疾病提及的概念归一化 | 适用 | 全部为英文病例与 SNOMED CT 映射 |
| 你要做中文临床文本 | 不适用 | 语言单一,无跨语言对齐 |
| 你要做药物或检验归一化 | 不适用 | 实体类别只有疾病 |
| 你要做端到端抽取加归一化 | 有条件适用 | 需另行取得原文 |
| 你要做单标签分类基准 | 不适用 | 多编号是设计核心 |
| 你要做概念版本迁移研究 | 部分适用 | 锁定 2016AB,可作为历史基准 |
| 你要做大规模预训练语料 | 不适用 | 总量一百多 KB |
| 你要做标注者分歧的定性研究 | 适用 | 论文给了一致性数字,且可拿到两份划分 |
4.6 三种最常见的误用方式
把这份语料放进一个真实项目,最常见的三种用法都是错的,而且错得不显眼。
| 误用 | 具体做法 | 为什么会错 | 改法 |
|---|---|---|---|
| 压成单标签 | 取第三列第一个编号当唯一答案 | 丢掉限定概念,§4.1 说过的信息在这里全灭 | 保留集合,用集合损失 |
| 当多标签分类 | 把每个编号当独立二分类标签 | 组合式的编号之间有主次关系,与并列的类别不同 | 加一个核心标记,或用集合口径评估 |
| 当泛化测试集 | 直接把全量成绩与开发包成绩并列 | 开发包全是难例,基数不同 | 分开报告,注明只含难例 |
第一种误用最普遍,因为它最省事,而且短期效果看起来不差——取第一个编号,严格口径的分数会略微上升,因为标注给出的第一个编号往往是核心概念。但这个上升是假象:模型从此只会输出核心概念,限定概念那一半的语义永久丢失。等到下游要把映射结果接到一个需要精细分型的任务上,缺失的部分就暴露出来。
第二种误用的根子在术语。多标签是机器学习里的通用说法,组合式是术语学里的专门说法,两者在数据结构上长得一样,在语义上不同。组合式里的每个编号承担不同角色:一个说明是什么,另一个说明在哪个部位、什么程度、什么病程。用标准的多标签损失训练,模型学不到角色,只学到"这些都常一起出现"。
第三种误用属于报告习惯。把两个基数不同的测试面直接并列,会让读者高估或低估系统,具体方向取决于系统擅长难例还是简单例。稳妥的写法是把全量成绩与难例成绩分成两行,并在表注里写清难例面的来源。
§5 怎么拿到:从压缩包到可训练样本
5.1 目录与下载面
PhysioNet 的目录是扁平的,根下四个文件,没有子目录。
| 路径 | 内容 | 大小 |
|---|---|---|
/files/cuiless16/1.0.0/CUILESS_DEV.tar.gz |
开发集 | 约 39 KB |
/files/cuiless16/1.0.0/CUILESS_TRAIN.tar.gz |
训练集 | 约 75 KB |
/files/cuiless16/1.0.0/semanticly_similiar_concept_sets.txt |
近似概念集 | 约 33 KB |
/files/cuiless16/1.0.0/SHA256SUMS.txt |
校验和 | 约 272 B |
全量下载不到一秒。这是它相对绝大多数临床 NLP 语料的一个实用优点——不需要申请、不需要排队、不需要几小时的传输。
5.2 下载与解包
#-- 一次取全四个文件,用官方校验和验证
base=https://physionet.org/files/cuiless16/1.0.0
mkdir -p cuiless16 && cd cuiless16
for f in CUILESS_TRAIN.tar.gz CUILESS_DEV.tar.gz \
semanticly_similiar_concept_sets.txt SHA256SUMS.txt; do
curl -sSLO "$base/$f"
done
sha256sum -c SHA256SUMS.txt
#-- 解开两个包,得到两个以包名命名的目录
tar -xzf CUILESS_TRAIN.tar.gz
tar -xzf CUILESS_DEV.tar.gz
ls CUILESS_TRAIN | head -3
解包后每个目录里是一批 .pipe 文件,文件名就是报告名。数量上,开发包与训练包各有上百份,具体以 ls | wc -l 为准,官方页面没有逐份列出。
5.3 校验和的坑
sha256sum -c 在某些情况下会失败,原因不是文件坏了,而是 SHA256SUMS.txt 里的路径前缀可能与本地解包后的相对路径不一致。遇到校验失败先打印清单内容看前缀,再决定是加 --ignore-missing 还是直接比对哈希值。
#-- 只比哈希值,绕开路径前缀问题
expected=$(grep 'CUILESS_DEV' SHA256SUMS.txt | awk '{print $1}')
actual=$(shasum -a 256 CUILESS_DEV.tar.gz | awk '{print $1}')
[ "$expected" = "$actual" ] && echo "DEV 校验通过" || echo "DEV 不一致"
第二段写的很短,是因为这类问题几乎每次都会遇到一次,写死在流程里比每次临时排查省事。
5.4 解析成表并做结构核对
import glob
import pandas as pd
COLS = ['report', 'span', 'cui', 'Norm_NI', 'Cue_NI', 'Norm_SC', 'Cue_SC',
'Norm_UI', 'Cue_UI', 'Norm_CC', 'Cue_CC', 'Norm_SV', 'Cue_SV',
'Norm_CO', 'Cue_CO', 'Norm_GC', 'Cue_GC', 'Norm_BL', 'Cue_BL']
def load(pattern):
frames = []
for path in sorted(glob.glob(pattern)):
df = pd.read_csv(path, sep='|', header=None, names=COLS,
dtype=str, keep_default_na=False,
na_values=['null'], engine='python')
frames.append(df)
return pd.concat(frames, ignore_index=True)
dev = load('CUILESS_DEV/*.pipe')
print(dev.shape) #-- 行数 = 提及数,列数 = 19
print(dev['cui'].str.split().str.len().value_counts().head())
#-- 只看 §4.3 的案例报告,确认三种形态都在
case = dev[dev['report'] == '00174-002042.text']
print(case[['span', 'cui', 'Norm_NI', 'Norm_BL']].head(8))
用 keep_default_na=False 再单独把 null 声明为缺失值,是有意的——第十八、十九列里可能出现看起来像数字的字符串,让 pandas 自己去猜类型会把它们变成浮点,Cue_BL 的区间就毁了。全程当字符串处理最稳。
5.5 拼上原文之后才能训练
概念编号本身不含语义,模型的输入必须是提及的文字。所以真正的训练流程要多一步:从 ShARe 语料里按报告名找到原文,再按区间切片。
def slice_mention(text, span):
#-- 区间可能是逗号分隔的多段,逐段切再拼
parts = []
for seg in span.split(','):
a, b = seg.split('-')
parts.append(text[int(a):int(b)])
return ' '.join(parts)
#-- text 需从 ShARe 原文取得;这里只演示切片逻辑
demo = 'patient presents with mild left lower lobe fibrosis'
print(slice_mention(demo, '0-7'))
第二段给的是一个假字符串,只演示切片。真跑的时候要把 ShARe 的原文读进来,按第一列的报告名对上号。对不上的报告要么是划分里没有、要么是版本不一致,两种情况都要记日志。
5.6 五个最容易出错的地方
| 位置 | 错误写法 | 后果 | 正确做法 |
|---|---|---|---|
| 文件名 | 把 similiar 改成 similar |
下载 404 | 照抄官方拼写 |
| 第三列 | 用空格切完只取第一个 | 组合式信息全丢 | 保留整个列表 |
| 划分 | 按提及随机切 | 同一报告跨两侧,泄漏 | 按报告名分组 |
| 缺失值 | 让 pandas 自动推断 | 区间被转成浮点 | 全列按字符串读 |
| 区间 | 当成闭区间 | 末尾多一个字或少一个字 | 按左闭右开处理 |
| 原文 | 直接用包里的坐标切 | 没有原文可切 | 先申请 ShARe 原文 |
§6 与库内相关词条的关系
6.1 关系图谱
库内与它相邻的资源分三类:术语本体本身、实体链接语料、临床文本语料。
| 资源 | 关系 | 与它的分工 |
|---|---|---|
| UMLS(统一医学语言系统) | 上游 | 提供概念编号体系,CUILESS2016 的编号全部来自这里 |
| SNOMED CT | 上游 | 提供临床概念与层级,组合式的拼接对象 |
| MedMentions | 同族 | 规模大、覆盖全部语义类型、单编号;CUILESS2016 小而深 |
| COMETA | 同族 | 社媒口语、双层标注;CUILESS2016 是病历书面语 |
| DisTEMIST | 同类思路的西班牙语版 | 同为疾病提及到 SNOMED CT 的映射,语言不同 |
| CANTEMIST | 相邻任务 | 做的是实体识别加 ICD-O 编码,不是概念归一化 |
| i2b2/n2c2 NLP | 上游语料来源生态 | 同为临床文本共享任务语料,任务类型不同 |
| MIMIC-IV-Note | 下游可用面 | 提供大规模真实病历文本,可与本语料的方法结合 |
| CRAFT | 参照 | 面向生物医学文献与全文标注,粒度更细 |
这张表里最值得记住的一行是 MedMentions。同为 UMLS 映射语料,两者构成了一个清晰的分工:MedMentions 解决"广",CUILESS2016 解决"深"。如果你的目标是把概念归一化的准确率从八成推到九成,第二份的作用远大于把 MedMentions 再训一轮。
6.2 检索路径
| 你要找的东西 | 检索词 | 会落到哪里 |
|---|---|---|
| 概念编号体系本身 | UMLS、CUI |
库内 UMLS 词条 |
| 临床概念的层级 | SNOMED CT、hierarchy |
库内 SNOMED CT 词条 |
| 大规模实体链接 | entity linking、MedMentions |
库内 MedMentions 词条 |
| 西班牙语同任务 | DisTEMIST、CANTEMIST |
库内两条西语语料 |
| 社媒口语映射 | COMETA、consumer health |
库内 COMETA 词条 |
| 临床原文来源 | ShARe、SemEval 2015 Task 14 |
外部,指向 QCRI 的任务页 |
6.3 与相近资源的区隔
三句话可以把区隔说干净:MedMentions 是"全类型、大样本、单编号",用来做广度;COMETA 是"口语、社媒、双层",用来测口语鲁棒性;CUILESS2016 是"单类型、小样本、多编号",用来攻最难的那一格。三者互不替代。库内还有两条西语的疾病到 SNOMED CT 映射语料,与它思路最近,差别在语言与标注深度——它们也不支持多编号拼接。
如果一定要给一个选型顺序:先看你需不需要组合式,需要就只剩它;不需要再看语言,英文选 MedMentions,西语选 DisTEMIST,口语选 COMETA。
6.4 与其他资源的组合用法
单独用它的场景有限,组合起来用才是常态。下面四种组合各自解决一个具体问题。
| 组合 | 做法 | 解决的问题 | 代价 |
|---|---|---|---|
| 加 UMLS | 用编号回查概念名与语义类型 | 编号本身没有语义,模型输入需要名字 | 需持 UMLS 许可,体积大 |
| 加 SNOMED CT | 沿层级扩展祖先与子概念 | 层级口径评估与概念合并 | 版本要与 2016AB 对齐 |
| 加 ShARe 原文 | 按报告名与区间切片 | 端到端训练的必要条件 | 需签协议并下载 |
| 加大规模映射语料 | 联合训练,难例加权 | 补偿训练样本不足 | 两套标注口径要统一 |
第一行的必要性常被低估。把概念编号直接当类别标签做分类,实际上是在做一个几十万类、每类只有编号没有语义的分类任务——类别之间的相似性完全不可用。回查概念名与语义类型之后,才能用嵌入、层级或词面相似度这些手段。UMLS 的许可与版本管理因此成了使用这份语料的前置条件。
第二行的版本对齐是硬约束。语料锁定 2016AB,如果手里的 SNOMED CT 是新版,沿层级扩展时可能遇到概念退役、合并、改名。稳妥的做法是先把新版层级投影回旧版,再算重合度,并在方法节写明版本。
第三行决定了训练流程的形状。原文与坐标分离,意味着任何端到端实验都要先做一次对号入座的工程活。这一步做不好,后面的模型再好也没用——切错一个字,整条样本的输入就废了。
第四行最难。大规模映射语料的标注往往是单编号,本语料是多编号,两套口径直接混合会让模型在两种输出格式之间摇摆。常见做法是给本语料的样本加一个权重,或者把多编号样本转成集合标签后与单编号样本统一编码。
§7 质量评估与局限性
7.0 阅读本节前的一个前置校正
评这份语料最容易犯的误判,是拿规模去否定它。一百多 KB、两千来个文件、五千余条提及,任何按"越大越好"排序的榜单里它都排末尾。但它的任务定义就是"只补最难那一格",规模小不是缺陷,是这个定义的直接后果——CUI-less 提及在全集里本来就是少数。
第二个容易误判的地方是把标注分歧当成标注错误。组合式归一化允许一个实体有多个合理的概念组合,两个标注者选出两组不同但语义覆盖相近的编号,这在设计上是允许的。严格口径 52.4% 的一致率,读法不是"标注质量差",而是"这个任务的合理答案本来就不唯一"。用单解假设去评它,分数一定难看。
7.1 五维评分
按 DAIMS 的常用维度打分,每项 1–5 分,分数针对"作为概念归一化研究语料"这个用途:
| 维度 | 分数 | 理由 |
|---|---|---|
| 数据规模 | 2 | 五千余条提及,训练集本身偏小 |
| 标注质量 | 3 | 有两人标注与一致性报告,但严格一致率仅五成出头 |
| 任务适配 | 5 | 组合式加难例,库内没有第二个这样的 |
| 文档完整 | 4 | 论文把方法与一致性写清,页面给了格式与许可 |
| 可获取性 | 5 | 免注册、体积极小、ODC-BY |
五项合计 19 分(满分 25)。结构上与很多小体量语料相似:规模拖后腿,适配拉满。不同的是它连标注质量也拿不到高分——这不是它的失误,是任务本身的性质。
7.2 两层评测口径
第一层是严格精确匹配。模型给出的编号集合与标注集合完全相等才算对。这个口径最严,也最容易被组合式标注惩罚:模型少给一个限定概念、或多给一个同义概念,都算错。
第二层是层级或集合口径。把编号映射到 SNOMED CT 的层级上,比较两者共享的祖先节点重合度;或者用近似概念集把同义编号视作等价。论文报告的 78.2% 用的就是前一类的思路。
| 口径 | 数值 | 对模型的要求 | 适用场景 |
|---|---|---|---|
| 严格精确匹配 | 52.4% | 概念组合完全一致 | 追求精确复现 |
| 层级节点重合 | 78.2% | 语义覆盖足够 | 临床可用的宽松评估 |
两个数字之间差的二十多个点,正是"组合式多解"的体量。这也是 §4.3 的案例想说明的事:同一段提及,两套编号可能都对,差别在于从哪里切分。
7.3 已知的、可枚举的偏差
| 偏差 | 表现 | 影响 |
|---|---|---|
| 单实体类型 | 只有疾病 | 药物、检验、操作类归一化无法覆盖 |
| 单语言 | 全部英文 | 跨语言迁移需另找数据 |
| 单地域 | 美国两家机构的病例 | 表达习惯与缩写有地域色彩 |
| 只含难例 | 全部为 CUI-less 提及 | 在它上面训出的模型到全集上可能偏保守 |
| 概念版本锁定 | UMLS 2016AB | 后续版本的退役与合并需自行处理 |
| 无原文 | 只有坐标 | 端到端流程必须外接 ShARe |
| 否定与不确定 | 线索列存在但常被忽略 | 只学提及到编号会误判否定句 |
倒数第二行与最后一行要连起来看。忽略否定标记是最常见的一类错误:模型看到"未见明显异常"里的"异常",照样给出一个阳性概念。线索列就在同一行里等着,不用是浪费。
7.4 外部验证矩阵
| 验证角色 | 做法 | 讲得通的地方 | 风险 |
|---|---|---|---|
| 难例压力测试 | 在全量上训练的模型直接跑开发包 | 全部是难例,掉分幅度真实 | 不能与全量成绩直接比较 |
| 组合式方法对比 | 与单编号系统在同一划分上比 | 划分统一,可比 | 严格口径会低估组合式系统 |
| 术语覆盖度研究 | 统计映射成功率 | 除个位数外的提及全部归上号 | 只覆盖疾病,不能推及全术语表 |
| 标注一致性复现 | 用两种口径复算 | 论文给了明确数字 | 需拿到原始双标注才能独立复算 |
| 多语言迁移起点 | 作为英文侧锚点与西语语料并置 | 同为疾病到 SNOMED CT | 相似性只在任务设定层面 |
第三行值得展开。论文的结论是组合式方法能提高语义覆盖度,直接的证据就是那几十条之外几乎全部归上号。这个结论的说服力来自"同一批提及、同一批标注者、只换映射规则"的对照,是很干净的实验设计。
7.5 它为何能持续:因为那一格没有别人
它没有扩版,没有版本迭代,讨论度也不算高,却一直留在 PhysioNet 的目录里。原因很直白:组合式概念标注的公开语料极少,而 CUI-less 这个具体问题在临床 NLP 里反复出现——只要医院还在用自由文本写病历,医生就还会写出标准词表装不下的表达。
它的生存逻辑不是"足够好",而是"位置唯一"。做术语工程的人需要一个可以引用的先例来说明组合式可行,这份语料就是那个先例。规模小反而降低了引用门槛:任何团队都能在几秒内拿到全量,用它做一个对照实验的成本几乎为零。
§8 生态位与历史
8.1 历史沿革
这份语料的历史要从前身讲起。ShARe 语料在 2013 年前后发布,是临床文本实体标注的一个公开基准,包含大量附有属性线索的疾病提及。2015 年的语义评测第 14 项任务在它上面设了归一化赛道,把"提及到概念"这一步作为独立任务。
评测结束后,几位参与者注意到一个遗留问题:被判为 CUI-less 的提及占了相当比例,却没有人专门处理。按评测的设定,这些提及在评分时被跳过,等于把最难的部分留在了场外。CUILESS2016 就是把场外的那部分捡回来,重新做了一遍。
这个路径很典型:共享任务产生数据,任务结束后有人回头补漏,补出来的东西成为新资源。
8.2 与其他补丁式资源的关系
临床 NLP 领域有不少"补丁式"资源:不算主流基准,但解决了某个具体缺口。CUILESS2016 在其中属于比较干净的一类——它只改一列,其余格式完全沿用,因此可以直接和原语料拼起来用。
| 资源类型 | 例子 | 与本语料的关系 |
|---|---|---|
| 原语料 | ShARe | 本语料的上游,提供文本与提及 |
| 评测任务 | SemEval-2015 Task 14 | 本语料的问题来源 |
| 补丁语料 | 本语料 | 只改概念列,补上难例 |
| 内部词表 | 近似概念集清单 | 评测时放宽同义 |
8.3 生态位:难例的尺子
| 角色 | 主力粮仓 | 难例尺 |
|---|---|---|
| 典型用法 | 大规模训练与预训练 | 压力测试、方法对照 |
| 需要的前提 | 量大、标签单一 | 全是难例、允许组合 |
| 代表资源 | MedMentions、MIMIC 病历 | 本语料 |
| 失败模式 | 标签覆盖不均 | 样本太少,结论不稳 |
衡量概念归一化系统的水平,全量测试集给的是平均值,本语料给的是下限。两者一起报,读者对系统的认识才完整。
8.4 谁在用它
从公开文献的引用看,使用者集中三类:做概念归一化方法对比的研究组,把开发包当难例集;做术语覆盖度评估的工程团队,用它量化 SNOMED CT 的表达缺口;做临床 NLP 教学的人,用它演示为什么"一病一码"在真实病历里会失效。第三类最少,但它最能说明这份语料的教学价值——一份报告就能讲清组合式。
§9 使用指引
9.1 三种角色的路径
| 角色 | 第一天 | 第一周 | 注意事项 |
|---|---|---|---|
| 临床 NLP 研究者 | 读论文摘要与页面,跑通 §2.3 的解析 | 在自己的模型上跑开发包,报两个口径 | 严格口径与层级口径都要报 |
| 术语与本体工程师 | 抽十行看第三列空格 | 统计概念复用情况,看哪些组合反复出现 | 不要用单标签框架去套 |
| 数据工程师 | 申请 ShARe 原文并签协议 | 把原文与坐标对上,跑通切片 | 版本号要对上,坐标才有意义 |
9.2 一条最短的可用流程
#-- 1. 取全量(几十 KB)
base=https://physionet.org/files/cuiless16/1.0.0
curl -sSLO "$base/CUILESS_DEV.tar.gz"
tar -xzf CUILESS_DEV.tar.gz
#-- 2. 确认结构:每个文件的行数即该报告的提及数
wc -l CUILESS_DEV/*.pipe | tail -1
#-- 3. 看一条多编号的行长什么样
grep -m 3 -E '\|[A-Z][0-9]+ [A-Z][0-9]+' CUILESS_DEV/*.pipe
第三段的 grep 是找第三列里带空格的写法。如果一条都找不到,说明包里的组合式标注极少,这对判断任务难度很关键;如果很多,就说明你的模型必须从一开始支持多标签输出。
import pandas as pd
COLS = ['report', 'span', 'cui', 'Norm_NI', 'Cue_NI', 'Norm_SC', 'Cue_SC',
'Norm_UI', 'Cue_UI', 'Norm_CC', 'Cue_CC', 'Norm_SV', 'Cue_SV',
'Norm_CO', 'Cue_CO', 'Norm_GC', 'Cue_GC', 'Norm_BL', 'Cue_BL']
dev = pd.read_csv('CUILESS_DEV/00174-002042.pipe', sep='|', header=None,
names=COLS, dtype=str, keep_default_na=False,
na_values=['null'])
print(dev['report'].nunique(), dev['cui'].str.count(' ').gt(0).sum())
9.3 引用方式
| 引用对象 | 内容 |
|---|---|
| 数据集 | CUILESS2016, version 1.0.0. PhysioNet. 2018. |
| 论文 | Osborne JD, Neu MB, Danila MI, Solorio T, Bethard SJ. CUILESS2016: a clinical corpus applying compositional normalization of text mentions. Journal of Biomedical Semantics 2018;9:2. |
| 平台 | PhysioNet 平台综述,按官方页面的 Cite 按钮生成 |
| 上游语料 | 若使用 ShARe 原文,须同时引用 ShARe 与 QCRI 的使用条款 |
写论文时建议注明:使用的划分(训练包或开发包)、概念版本(UMLS 2016AB)、评测口径(严格或层级)。
§10 AI 使用声明
| 项目 | 声明 |
|---|---|
| 文本生成 | 本文由 AI 辅助撰写,编辑把关结构与事实 |
| 数字来源 | 规模、结构、边界三类数字来自 PhysioNet 官方页面与论文摘要 |
| 文件核验 | 两个压缩包已下载解包,确认文件形态与 19 列结构 |
| 论文信息 | 仅参考 Europe PMC 返回的摘要,未读全文 |
| 未核验内容 | 每个概念编号的具体名称、双标注原始文件、逐份报告的行数 |
| 不做的事 | 未统计概念频次、未做空值率交叉表、未计算任何分布 |
| 原文 | 未申请 ShARe 原文,切片逻辑仅作演示 |
| 免责 | 本文不构成临床或术语标准建议;使用须遵守 ODC-BY 1.0 署名 |
常见误读(避坑清单)
| 说法 | 实际 | 证据 |
|---|---|---|
| 「这是无袖带血压数据集」 | CUI 指概念唯一标识符,全库无生理信号 | 包内全部为 .pipe 文本 |
| 「CUILESS 是 cuffless 的另一种拼法」 | 两者只读音相近,含义无关 | 官方简介首句写明 CUI-less 的含义 |
| 「它就是 ShARe 语料」 | 只取其中被判为 CUI-less 的疾病提及 | 页面 Data Collection 段 |
| 「它自带临床原文」 | 原文不随包分发,须另向 QCRI 申请 | 页面明确写 clinical text is not distributed |
| 「一个提及只有一个概念」 | 第三列可含多个编号,空格分隔 | 页面 Files 段与样例行 |
| 「它覆盖药物与检验实体」 | 只有疾病一类 | 论文摘要只言 disorder mentions |
| 「标注一致性差说明标注不可靠」 | 组合式任务本身存在多解 | 摘要给出两个口径的数字 |
| 「文件名拼错了是 bug」 | 官方就是 similiar,照抄才能下载 |
官方文件目录 |
| 「它的概念编号是最新版 SNOMED CT」 | 锁定 UMLS 2016AB 内的 2016 年 9 月版 | 页面简介段 |
| 「可以按提及随机划分训练测试」 | 应按报告分组,避免同报告泄漏 | 两包的划分单位是报告 |
FAQ
Q1:CUILESS2016 是无袖带血压数据集吗?
不是。CUI 是 Concept Unique Identifier 的缩写,less 表示这些疾病提及原本找不到对应的单个概念。全库没有任何生理信号或血压值。它和 cuffless 只撞了读音,与心血管测量没有任何关系。
Q2:它和 ShARe、SemEval-2015 Task 14 什么关系?
ShARe 提供原文与提及标注,Task 14 是在它上面办的归一化评测。本语料从同一批提及中挑出评测判为 CUI-less 的部分重做映射,继承原有区间与线索列,只改动概念列。
Q3:为什么一个病会有好几个概念编号?
因为采用组合式表达。SNOMED CT 里没有现成的单一概念能装下某些复合表达,标注者就用核心概念加限定概念来拼。这是设计意图,不是标注错误。
Q4:没有原文能用吗?
能用于评测与训练概念映射,但必须向 QCRI 取得 ShARe 原文并签协议。只有坐标时,能做的只剩概念粒度层面的分析。
Q5:一致性只有一半多,是不是标注质量不行?
不是。这是组合式任务的固有性质:同一个病可以有多种语义覆盖相近的编号组合。严格口径判这些为不一致,层级口径则认可。用它训练时损失函数要容忍多解。
Q6:训练集和开发集怎么分?
直接用官方两个包,不要自行打乱。划分按报告进行,自行按提及切分会让同一份报告跨两侧。
Q7:概念编号是哪一版 SNOMED CT?
UMLS 2016AB 内嵌的 2016 年 9 月版。后续版本的概念退役与合并要自行处理,不能直接套新表。
Q8:它能不能做中文?
不能直接用。全部是英文病历,表达习惯与缩写都是美式的。做中文需要另找语料,或用它做方法验证后再迁移。
Q9:体量这么小,能训出模型吗?
单靠它训不出可用的通用模型。它的正确用法是难例测试集,或与更大的 UMLS 映射语料联合训练时做难例加权。
Q10:许可允许商用吗?
ODC-BY 1.0 允许包括商业用途在内的一切使用,条件是署名。原文部分的许可另算,归 ShARe 与 QCRI 的数据使用协议管。
Q11:semanticly_similiar_concept_sets.txt 是干什么的?
收录语义上可互换的概念集合,用于评估时把同义编号视作等价,让层级或集合口径可以落地。文件名拼写以官方为准。
Q12:为什么版本停在 1.0.0?
官方没有给出扩版说明。从资源性质看,它是对一个已结束评测的补漏,补完即完成,不像活体数据库那样需要持续维护。
术语表
| 术语 | 解释 |
|---|---|
| 概念归一化 | 把文本里的医学表达映射到标准术语表中的编号 |
| CUI | UMLS 中的概念唯一标识符,形如 C 加七位数字 |
| CUI-less | 找不到单个预制概念可映射的提及,共享任务里的标记 |
| UMLS | 统一医学语言系统,跨词表的概念集成枢纽 |
| SNOMED CT | 临床术语体系,含概念层级与关系 |
| 预制概念 | 术语表里已经定义好的单一概念 |
| 后组合 | 用多个概念加限定关系描述一个复合概念 |
| 组合式概念 | 本文语料的核心做法,多个编号并置,不限关系 |
| 语义类型 | UMLS 给概念分的类别,如疾病、解剖、药物 |
| ShARe 语料 | 临床文本实体标注语料,本语料的上游 |
| SemEval-2015 Task 14 | 在 ShARe 上办的归一化评测任务 |
| 提及 | 文本中指向某个实体的一段字 |
| 字符区间 | 提及起止的字符位移,左闭右开 |
| 线索 | 表示否定、严重度、时间等的词或短语 |
| 否定标记 | 表示该提及在语义上被否定的线索 |
| 不确定标记 | 表示提及存在可能性的线索 |
| 主语归属 | 提及描述的是患者本人还是家属 |
| 标注一致性 | 多名标注者对同一对象结论的吻合程度 |
| 严格精确匹配 | 概念集合完全相等才算对的评测口径 |
| 层级节点重合 | 比较概念在层级树上的共享祖先,宽松口径 |
| 近似概念集 | 语义可互换的概念分组,评估时放宽用 |
| 管道分隔 | 用竖线作字段分隔符的纯文本格式 |
| 左闭右开 | 区间含起点不含终点的约定 |
| 报告级划分 | 以报告为单位切分训练与测试,避免泄漏 |
| QCRI | 卡塔尔计算研究所,ShARe 原文的分发方 |
| ODC-BY | 开放数据共享署名许可,允许商用需署名 |
| PhysioNet | 由 MIT 等机构维护的生物医学数据平台 |
附录 A:核心数字核对表
| 项 | 值 | 来源 | 来源层级 |
|---|---|---|---|
| 提及总数 | 见速览表 | 官方页面与论文摘要一致 | 官方页面 |
| 未能归一化的条数 | 8 | 论文摘要 | 论文摘要 |
| 严格口径一致性 | 52.4% | 论文摘要 | 论文摘要 |
| 层级口径一致性 | 78.2% | 论文摘要 | 论文摘要 |
| 每行字段数 | 19 | 解包后逐行确认 | 官方文件 |
| 概念体系版本 | UMLS 2016AB 的 2016 年 9 月版 | 官方页面 | 官方页面 |
| 上线日期 | 2018-01-24 | 官方页面 | 官方页面 |
| 版本号 | 1.0.0 | 官方页面 | 官方页面 |
| 训练包大小 | 约 75 KB | 官方文件目录 | 官方文件 |
| 开发包大小 | 约 39 KB | 官方文件目录 | 官方文件 |
| 近似概念集大小 | 约 33 KB | 官方文件目录 | 官方文件 |
| 解压后总大小 | 约一百四十余 KB | 官方页面 | 官方页面 |
| 许可 | ODC-BY 1.0 | 官方页面 | 官方页面 |
| DOI | 10.13026/C2F66G | 官方页面 | 官方页面 |
| 部门报告数 | 官方未公布 | — | 未公布 |
| 单编号与多编号占比 | 官方未公布 | — | 未公布 |
附录 B:数字的来源分层
第一层:官方页面与官方文件。 提及总数、概念体系版本、上线日期、版本号、三个文件的体积、解压总量、许可、DOI、每行 19 列的结构、原文不分发的声明。这些来自项目主页与解包后的文件本身。
第二层:论文摘要。 除八条之外全部归一化成功、两种口径的标注一致率、方法与动机的表述。摘要只能支撑方法与结论,不能支撑逐条实验细节。
第三层:未核实。 每份报告的具体提及数、单编号与多编号各自的比例、概念编号的名称与层级、双标注原始文件的差异分布。这些需要拿到原文与 UMLS 逐条查询,超出本文范围,正文涉及之处只做定性表述。
附录 C:完整参考文献
| 编号 | 文献 | 链接 | 用途 |
|---|---|---|---|
| 1 | CUILESS2016 v1.0.0 项目页 | https://physionet.org/content/cuiless16/1.0.0/ | 规模、结构、许可、日期 |
| 2 | 该项目的文件目录 | https://physionet.org/files/cuiless16/1.0.0/ | 三个文件与体积 |
| 3 | Osborne JD 等,CUILESS2016 论文 | https://doi.org/10.1186/s13326-017-0173-6 | 方法、一致性数字、结论 |
| 4 | PhysioNet 平台综述 | https://doi.org/10.1038/s44360-026-00096-z | 托管与引用规范 |
| 5 | SemEval-2015 Task 14 任务页 | http://alt.qcri.org/semeval2015/task14/ | 前身任务与原文申请入口 |
| 6 | Europe PMC 检索 | https://www.ebi.ac.uk/europepmc/ | 摘要核对 |
| 7 | 库内 UMLS 词条 | 站内 | 概念体系背景 |
| 8 | 库内 SNOMED CT 词条 | 站内 | 术语层级背景 |
附录 D:任务代码
任务一:把开发包拆成「提及文本 + 概念集合」的样本表
import glob
import pandas as pd
COLS = ['report', 'span', 'cui', 'Norm_NI', 'Cue_NI', 'Norm_SC', 'Cue_SC',
'Norm_UI', 'Cue_UI', 'Norm_CC', 'Cue_CC', 'Norm_SV', 'Cue_SV',
'Norm_CO', 'Cue_CO', 'Norm_GC', 'Cue_GC', 'Norm_BL', 'Cue_BL']
def spans(span_field):
out = []
for seg in span_field.split(','):
a, b = seg.split('-')
out.append((int(a), int(b)))
return out
rows = []
for path in sorted(glob.glob('CUILESS_DEV/*.pipe')):
df = pd.read_csv(path, sep='|', header=None, names=COLS, dtype=str,
keep_default_na=False, na_values=['null'])
for _, r in df.iterrows():
rows.append({
'report': r['report'],
'segments': spans(r['span']),
'cuis': set(r['cui'].split()),
'negated': r['Norm_NI'] == 'yes',
})
samples = pd.DataFrame(rows)
print(samples.shape)
print(samples['cuis'].apply(len).value_counts().sort_index())
第二段打印的是每个提及带几个概念。它是结构核对,不是分布结论——只看形态有几档,不做频次排名。
任务二:用严格口径与集合口径各算一次命中
def strict_hit(pred, gold):
return set(pred) == set(gold)
def relaxed_hit(pred, gold, groups):
#-- groups: 概念 -> 近似集合编号;任一 pred 与 gold 落同组即算部分覆盖
def g(c):
return groups.get(c, c)
return bool({g(c) for c in pred} & {g(c) for c in gold})
def load_groups(path):
groups = {}
for line in open(path, encoding='utf-8'):
members = line.split()
for m in members:
groups[m] = members[0]
return groups
groups = load_groups('semanticly_similiar_concept_sets.txt')
gold = {'C0424000'}
pred = {'C0424000', 'C0027763'}
print(strict_hit(pred, gold), relaxed_hit(pred, gold, groups))
第二段代码给的是评测口径的骨架,groups 的构造方式取决于清单的实际格式,用之前先 head 看一眼。
附录 E:如果只记五件事
| 序号 | 记住什么 | 为什么 |
|---|---|---|
| 1 | 它是概念归一化语料,不是血压数据 | 库名缩写误导了很多人 |
| 2 | 规模五千余条提及,只覆盖难例 | 决定了它只能当尺子不能当粮仓 |
| 3 | 一个实体可对多个概念编号 | 这是它唯一独有的信息,压成单标签就丢了 |
| 4 | 原文不随包,须向 QCRI 申请 | 端到端流程的前提 |
| 5 | 一致性按两个口径报,别只报一个 | 严格口径会低估组合式系统 |
编辑说明
核验时间为 2026 年 10 月 28 日。核对方式为直接访问 PhysioNet 项目页,并下载两个压缩包解包确认文件形态为以报告号命名的管道分隔文本、每行十九列、第三列可出现空格分隔的多个概念编号;论文侧只检索 Europe PMC 的摘要,未读全文。两份包的 .pipe 文件数分别在一百三十余与两百七十余,官方未在页面上逐份列出,正文只写"上百份"这一量级。未覆盖的内容包括:每个概念编号的名称与层级、单编号与多编号的占比、双标注原始文件的差异分布、以及逐份报告的提及数。全文未做概念频次、空值率与任何分布统计,附录 A 中标注"未公布"的两项即为此类。库名缩写与 cuffless 的读音相近导致误检,这一点在导语、§1.2、常见误读与 FAQ 首问各提一次,因为它是这个库名最主要的检索噪音来源。
相关数据集导航
以下为站内 AI-Ready 数据集百科中与本词条共享多个主题标签的相关数据集,按相关度降序排列:
- distemist — 共享标签:医疗NLP / 临床文本 / 知识图谱
- snomed-ct — 共享标签:医疗NLP / 临床文本 / 知识图谱
- umls — 共享标签:医疗NLP / 临床文本 / 知识图谱
- loinc — 共享标签:医疗NLP / 临床文本 / 知识图谱
- mimic-iv-ext-pe — 共享标签:医疗NLP / 临床文本
- rad-coreference-resolution — 共享标签:医疗NLP / 临床文本
- radgraph2-radiology-reports — 共享标签:医疗NLP / 临床文本
- qizheng-gpt — 共享标签:医疗NLP / 临床文本 / 知识图谱
- imcs-21 — 共享标签:医疗NLP / 临床文本
- slake — 共享标签:医疗NLP / 知识图谱
导航说明:本章节由全站统一标签体系自动计算生成(标签重合度算法),双向可达;点击链接可跳转至对应数据集词条。

