spaCy自定义管道中Matcher无法匹配文本的问题求助
我是spaCy新手,正在学习使用Matcher从演员维基百科页面提取出生日期(DOB),例如:
Scarlett Ingrid Johansson (/dʒoʊˈhænsən/;[1] born November 22, 1984) is an American actress. The world's highest-paid actress in 2018 and 2019, she has featured multiple times on the Forbes Celebrity 100 list.
我尝试匹配born November 22, 1984格式的内容,提取日期并标记为"DOB"。我的代码直接对doc对象运行时可得到预期结果,但将其加入自定义管道后却无法匹配任何内容。
我的匹配模式代码:
nlp = spacy.load("en_core_web_sm") # pattern for `born MM DD, YYYY` born_pattern = [{'LOWER': 'born'}, {'ENT_TYPE': 'DATE'}, {'ENT_TYPE': 'DATE'}, {'ORTH': ','}, {'ENT_TYPE': 'DATE'}] matcher = Matcher(nlp.vocab) matcher.add("DOB", [ born_pattern ])
直接测试代码时输出符合预期:
testdoc = nlp("Alex, born January 22, 1960, is an athlete.") matches = matcher(testdoc) for match_id, start, end in matches: # grab the date print( testdoc[start+1:end])
输出:January 22, 1960
但加入管道后无匹配结果:
@Language.component("dob_component") def dob_component_function(doc): # Create an entity Span with the label "DOB" for all matches matches = matcher(doc) print("Matches found: ", len(matches)) # the `start+1` will skip the "born" token doc.ents = list(doc.ents) + [Span(doc, start+1, end, label="DOB") for match_id, start, end in matches] return doc nlp.add_pipe("dob_component", before="ner") print(nlp.pipe_names) # output # ['tok2vec', # 'tagger', # 'parser', # 'attribute_ruler', # 'lemmatizer', # 'dob_component', # 'ner'] testdoc = nlp("Alex, born January 22, 1960, is an athlete.") #output # Matches found: 0
关键原因:你的匹配模式依赖ENT_TYPE: DATE,但这个标签是由spaCy的ner组件标注的。你把自定义管道dob_component加在了ner之前,此时处理doc时,NER还没运行,所有token的ENT_TYPE都是空值,自然匹配不到任何结果。
有两种解决办法:
办法一:调整管道顺序到NER之后
把自定义管道放在ner组件之后,这样NER已经完成了实体标注,ENT_TYPE有值就能匹配:
# 替换原来的add_pipe语句 nlp.add_pipe("dob_component", after="ner")
办法二:修改匹配模式,不依赖NER的ENT_TYPE
如果必须在NER之前运行组件,可以用其他特征来匹配日期,比如利用IS_DATE属性(spaCy的token自带的日期判断),或者匹配月份文本、数字格式:
# 示例:用IS_DATE和标点匹配 born_pattern = [ {'LOWER': 'born'}, {'IS_DATE': True}, {'IS_DATE': True}, {'ORTH': ','}, {'IS_DATE': True} ] # 或者更精确的月份+数字+逗号+年份模式 month_list = ["january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december"] born_pattern = [ {'LOWER': 'born'}, {'LOWER': {'IN': month_list}}, {'LIKE_NUM': True}, {'ORTH': ','}, {'LIKE_NUM': True, 'LENGTH': 4} ]
注意:使用IS_DATE需要确保spaCy的tokenizer正确识别日期,而用月份列表的方式更精准,适合固定格式的出生日期匹配。
内容的提问来源于stack exchange,提问作者user3377465

