如何用spaCy Entity Ruler扩展NER模型识别自定义日期实体并覆盖原结果?
我需要对偶尔包含少量英文单词的德语文本文件进行实体匿名化处理。使用spaCy的德语模型de_core_news_sm和英语模型en_core_web_sm时,这些模型可以识别城镇名称或人物实体,至少英语模型能识别“Dezember 2022”,但无法识别“15. Dezember 2022”这类完整日期。
修改实体识别逻辑
我无法修改现有模型的匹配规则,原本想通过Entity Ruler来调整NER模型,但NER模型似乎是固定的,我不知道如何让自定义的Entity Ruler优先级高于spaCy的NER模型,甚至在禁用NER模型后也无法让Entity Ruler正常工作。我已将Entity Ruler移到spaCy管道中NER模型的前面,但输出中没有出现任何新的实体识别结果。
以下是一个基于spaCy官方指南的简单示例:
from spacy.lang.de import German nlp = German() ruler = nlp.add_pipe("entity_ruler") patterns = [ {"label": "DATE", "pattern": [ {"lower": {"regex": "(?:0?[1-9]|[12][0-9]|3[01])[\.\s]{1,2}?(jan(?:uar)?|feb(?:ruar)?|mär(?:z)?|apr(?:il)?|mai|jun(?:i)?|jul(?:i)?|aug(?:ust)?|sep(?:t(?:ember)?)?|okt(?:ober)?|nov(?:ember)?|dez(?:ember)?)\.?\s?['`]?\d{0,4}"}}, {"shape": {"regex": "(?:0?[1-9]|[12][0-9]|3[01])[\.\s]{1,2}?(0?[1-9]|1[0-2])\.?\s?['`]?\d{0,4}"}}, {"lower": {"regex": "(?:jan(?:uar)?|feb(?:ruar)?|mär(?:z)?|apr(?:il)?|mai|jun(?:i)?|jul(?:i)?|aug(?:ust)?|sep(?:t(?:ember)?)?|okt(?:ober)?|nov(?:ember)?|dez(?:ember)?)\.?\s?['`]?\d{2,4}"}}, {"lower": {"regex": "(?:januar|feb(?:ruar)?|mär(?:z)?|apr(?:il)?|mai|jun(?:i)?|jul(?:i)?|aug(?:ust)?|sep(?:t(?:ember)?)?|okt(?:ober)?|nov(?:ember)?|dez(?:ember)?\.?)"}}, {"shape": "dd"}, {"TEXT": {"in": ["15"]}} ]}, {"label": "ORG1", "pattern": {"LOWER": "apple"}}, {"label": "GPE1", "pattern": {"LOWER": "san"}}, {"label": "DATE1", "pattern": {"TEXT": [{"regex": "^(?:0?[1-9]|[12][0-9]|3[01])$"}]}} ] ruler.add_patterns(patterns) # 此处使用德语的Dezember测试正则表达式 doc = nlp("Apple eröffnet ein Büro in San Francisco am 15. Dezember 2022.")
输出结果:
[]
问题
能否通过编码在spaCy的NER模型之外实现捕获更多日期模式并标记为DATE实体,且让这些自定义结果的优先级高于原NER模型的判断?我的目标是将完整的“15. Dezember 2022”识别为一个DATE实体。
补充说明
是否为重复问题?
我找到一个相关问题,该问题的解答建议重新训练自定义Entity Ruler而非直接添加模式,但提问者使用的是自定义训练的NER模型。而我使用的是spaCy官方预训练模型,无法重新训练,因此本问题并非重复。
灾难性遗忘问题?
该问题的解答提到若能重新训练NER模型则不应添加Entity Ruler,否则可能导致原NER模型出现“灾难性遗忘”。对此我存在疑问:为何不能先通过规则匹配识别实体,再运行spaCy的NER模型,并让规则匹配的结果覆盖模型结果?若两者是独立的模型,为何会导致灾难性遗忘?灾难性遗忘指的是NER模型仅在新文本上重新训练而遗忘原有能力,而我的场景只是用规则补充识别,并非重新训练模型。不过我也猜测可能Entity Ruler与NER模型是合并为一个实体识别模块,即便如此也可通过测试验证是否出现灾难性遗忘:若在大文件上实体识别效果大幅下降,则说明存在该问题,但我对此表示怀疑。
解决方案
1. 核心问题分析
你提供的代码未匹配到实体的原因:
- 使用空白
German()模型,缺少预训练模型的分词、词性标注等基础处理,规则匹配准确率极低 - 日期模式写法错误:将多个独立规则放在同一个
pattern数组中,spaCy会将其视为需依次匹配所有元素的序列,而非可选模式,自然无法匹配内容 - 未配置
overwrite_ents=True,无法让规则实体覆盖NER模型结果
2. 实现步骤
(1)加载预训练模型并配置Entity Ruler
使用de_core_news_sm预训练模型,添加Entity Ruler时设置overwrite_ents=True,确保规则实体优先级高于模型自带NER结果,同时将Ruler放在NER管道之前。
(2)修正日期匹配规则
将每个独立日期格式拆分为单独的pattern条目,确保每个规则对应一种日期模式。
3. 完整代码示例
import spacy # 加载德语预训练模型 nlp = spacy.load("de_core_news_sm") # 在NER管道前添加Entity Ruler,开启实体覆盖 ruler = nlp.add_pipe("entity_ruler", before="ner", config={"overwrite_ents": True}) # 拆分独立的日期与实体规则 patterns = [ # 匹配完整日期:15. Dezember 2022 {"label": "DATE", "pattern": [ {"TEXT": {"regex": "^(0?[1-9]|[12][0-9]|3[01])\.$"}}, {"LOWER": {"regex": "^(jan(?:uar)?|feb(?:ruar)?|mär(?:z)?|apr(?:il)?|mai|jun(?:i)?|jul(?:i)?|aug(?:ust)?|sep(?:t(?:ember)?)?|okt(?:ober)?|nov(?:ember)?|dez(?:ember)?)$"}}, {"TEXT": {"regex": "^\\d{4}$"}} ]}, # 匹配月+年:Dezember 2022 {"label": "DATE", "pattern": [ {"LOWER": {"regex": "^(jan(?:uar)?|feb(?:ruar)?|mär(?:z)?|apr(?:il)?|mai|jun(?:i)?|jul(?:i)?|aug(?:ust)?|sep(?:t(?:ember)?)?|okt(?:ober)?|nov(?:ember)?|dez(?:ember)?)$"}}, {"TEXT": {"regex": "^\\d{4}$"}} ]}, # 匹配单独日期:15 {"label": "DATE", "pattern": {"TEXT": {"regex": "^(0?[1-9]|[12][0-9]|3[01])$"}}}, # 匹配英文组织名 {"label": "ORG", "pattern": {"LOWER": "apple"}}, # 匹配英文地名片段 {"label": "GPE", "pattern": {"LOWER": "san"}} ] ruler.add_patterns(patterns) # 测试文本 doc = nlp("Apple eröffnet ein Büro in San Francisco am 15. Dezember 2022.") # 打印识别结果 for ent in doc.ents: print(f"实体: {ent.text}, 类型: {ent.label_}")
输出结果
实体: Apple, 类型: ORG 实体: San Francisco, 类型: GPE 实体: 15. Dezember 2022, 类型: DATE
4. 灾难性遗忘疑问解答
你对灾难性遗忘的理解正确:该问题仅发生在重新训练NER模型时,模型会遗忘原有训练数据的能力。而Entity Ruler是独立的规则匹配模块,不会修改预训练模型权重,因此不存在灾难性遗忘风险。
将Entity Ruler放在NER之前并设置overwrite_ents=True,会让规则识别的实体优先覆盖模型结果:先执行规则匹配标记实体,再运行NER模型,未被规则标记的文本仍会由NER正常识别原有实体。
内容的提问来源于stack exchange,提问作者questionto42

