基于SciSpacy的生物医学短文本实体链接多候选实体处理咨询
兼容SciSpacy的UMLS实体链接优化策略(无需微调)
针对短文本生物医学实体链接中的噪声问题(错误匹配泛称实体、遗漏关键缩写实体),以下是基于SciSpacy现有能力、结合UMLS本体特性的后处理优化方案,无需微调模型:
1. UMLS本体特异性过滤(解决泛称噪声)
核心思路
利用UMLS实体的语义层级与特异性,过滤泛称实体(如diseases、Standard),保留更具体的目标实体:
- 从UMLS本地数据或离线文件中,获取每个候选实体的语义层级深度(通过
IS_A关系链长度判断,层级越深越具体)或原子性标记(UMLS中ATOMIC字段为Y表示原子实体,即具体概念)。 - 仅保留层级深度≥3或原子性为
Y的实体,同时过滤属于通用语义类别的实体(如Standard属于TUIT070[Qualitative Concept],直接排除)。
代码示例(基于SciSpacy结果)
import spacy # 加载SciSpacy生物医学NER模型(已集成UMLS链接) nlp = spacy.load("en_ner_bc5cdr_md") # 假设已加载本地UMLS元数据映射(CUI -> 层级深度/原子性) umls_cui_meta = {"C0002395": {"depth": 4, "atomic": "Y"}, # Alzheimer's "C0012634": {"depth": 1, "atomic": "N"}, # diseases "C0027651": {"depth": 3, "atomic": "Y"}} # NEC def filter_generic_entities(doc): filtered_ents = [] for ent in doc.ents: cui = ent._.umls_cui if cui not in umls_cui_meta: continue # 保留特异性高的实体 if umls_cui_meta[cui]["depth"] >= 3 or umls_cui_meta[cui]["atomic"] == "Y": filtered_ents.append(ent) doc.ents = filtered_ents return doc # 测试示例文本 text = "Standard PRS for Alzheimer's" doc = nlp(text) filtered_doc = filter_generic_entities(doc) # 结果仅保留Alzheimer's print([(ent.text, ent._.umls_cui) for ent in filtered_doc.ents])
2. 短文本语境约束调整(解决实体优先级倒置)
核心思路
针对SciSpacy优先匹配早出现实体的问题,通过规则调整实体匹配优先级:
- 长度优先规则:对候选实体按文本长度倒序排序,优先保留长实体或缩写扩展后的长实体(如
NEC扩展为Necrotizing enterocolitis,长度更长,优先匹配)。 - 修饰词排除规则:过滤掉被
Standard、Other等修饰词前置的泛称实体(如Other diseases中的diseases直接排除)。
代码示例
def adjust_entity_priority(doc): # 按实体文本长度倒序排序(若有缩写扩展,用扩展后长度) sorted_ents = sorted(doc.ents, key=lambda x: len(x.text), reverse=True) # 过滤修饰词前置的泛称实体 filtered_ents = [] for ent in sorted_ents: # 检查实体前一个词是否为修饰词 if ent.start > 0: prev_token = doc[ent.start-1] if prev_token.text.lower() in ["standard", "other", "general"]: # 若实体是泛称(如diseases),跳过 if ent._.umls_cui == "C0012634": continue filtered_ents.append(ent) # 去重(保留优先级高的实体) unique_ents = [] seen_cuis = set() for ent in filtered_ents: if ent._.umls_cui not in seen_cuis: seen_cuis.add(ent._.umls_cui) unique_ents.append(ent) doc.ents = unique_ents return doc # 测试示例文本 text = "Other diseases of respiratory system, NEC" doc = nlp(text) adjusted_doc = adjust_entity_priority(doc) # 结果优先保留NEC,过滤diseases print([(ent.text, ent._.umls_cui) for ent in adjusted_doc.ents])
3. 相对语义相似度过滤(解决无通用阈值问题)
核心思路
放弃固定阈值,改用相对相似度排名结合UMLS语义类别过滤:
- 使用预训练生物医学Sentence-BERT模型,计算输入短文本与每个候选实体的UMLS定义文本的余弦相似度。
- 保留相似度排名前2的实体,同时确保至少有一个属于目标语义类别(如疾病类TUI
T047)。
代码示例
from sentence_transformers import SentenceTransformer, util # 加载预训练生物医学Sentence-BERT模型 model = SentenceTransformer("pritamdeka/BioBERT-mnli-snli-scinli-scitail-mednli-stsb") # 假设已加载UMLS CUI对应的定义文本 umls_cui_defs = {"C0027651": "Necrotizing enterocolitis is a severe intestinal disease...", "C0012634": "A disease is an abnormal condition affecting body function..."} def filter_by_relative_similarity(doc, input_text): # 计算输入文本的嵌入 input_emb = model.encode(input_text, convert_to_tensor=True) # 计算每个候选实体的相似度 ent_scores = [] for ent in doc.ents: cui = ent._.umls_cui if cui not in umls_cui_defs: continue def_emb = model.encode(umls_cui_defs[cui], convert_to_tensor=True) sim_score = util.cos_sim(input_emb, def_emb).item() ent_scores.append((ent, sim_score)) # 按相似度降序排序,保留前2 ent_scores.sort(key=lambda x: x[1], reverse=True) filtered_ents = [ent for ent, score in ent_scores[:2]] doc.ents = filtered_ents return doc # 测试示例文本 text = "Other diseases of respiratory system, NEC" doc = nlp(text) filtered_doc = filter_by_relative_similarity(doc, text) print([(ent.text, ent._.umls_cui) for ent in filtered_doc.ents])
4. 组合策略(最优方案)
将上述三种策略按顺序组合:
- 先通过修饰词排除规则过滤明显噪声;
- 再通过UMLS特异性过滤保留具体实体;
- 最后通过相对相似度排名调整最终结果。
这种组合既能解决泛称噪声,又能纠正实体优先级倒置问题,且完全兼容SciSpacy,无需微调模型。
内容的提问来源于stack exchange,提问作者GrimSqueaker
相关产品推荐
相关产品推荐

