自定义spaCy词性标注器报错:未注册扩展属性pos_tag无法分配
解决spaCy自定义标注器的AttributeError(E047)问题
错误原因分析
你遇到的AttributeError: [E047]是因为:
- 未正确导入
Token类就尝试注册扩展,且错误使用Doc而非Token来注册token级别的扩展 - 自定义管道的初始化和添加逻辑冲突,手动实例化标注器但未正确关联到nlp流程
- 扩展注册时机不正确,导致spaCy无法识别自定义的
pos_tag属性
分步解决方案
1. 正确注册Token扩展属性
要给单个token添加自定义扩展属性,需导入spaCy的Token类并完成注册:
from spacy.tokens import Token # 注册token级别的扩展属性,允许覆盖已有同名扩展 Token.set_extension('pos_tag', default=None, force=True)
2. 修正自定义标注器的管道添加逻辑
不需要手动实例化KeywordPosTagger,nlp.add_pipe会通过你定义的Language.factory自动创建实例。同时config参数无需传递nlp,spaCy会自动注入该参数。
3. 完整修正后的代码
import requests import spacy from spacy.tokens import Token from spacy.language import Language # 注册token扩展属性 Token.set_extension('pos_tag', default=None, force=True) # 加载外部词典(保留原代码定义,若后续需使用可直接调用) dictionary = requests.get( "https://github.com/dglopes/NBR15575/raw/main/unidades_medidas.json").json() # 定义自定义标注器Factory @Language.factory("keyword_pos_tagger") class KeywordPosTagger: def __init__(self, name, nlp, keywords, pos_tag): self.keywords = keywords self.pos_tag = pos_tag def __call__(self, doc): for token in doc: if token.text in self.keywords: token._.pos_tag = self.pos_tag return doc # 加载葡萄牙语预训练模型 nlp = spacy.load('pt_core_news_md') # 配置目标关键词和自定义POS标签 keywords = ('m²', 'm2', '(W/K)', 'ºC') pos_tag = 'UNM' # 将自定义标注器添加到nlp处理流程 nlp.add_pipe('keyword_pos_tagger', config={"keywords": keywords, "pos_tag": pos_tag}) # 测试调用 doc = nlp('A temperatura tem 159ºC ou 20 ºC. Também precisa ter 20m de largura e 14 m² de área, caso contrário terá 1 Kelvin (W/K)') for token in doc: print(token.text, token._.pos_tag)
额外需求:将自定义标签赋值给token.pos_
如果希望自定义标签像内置的NOUN/VERB一样直接赋值给token.pos_(而非扩展属性),需要先将自定义标签添加到spaCy词汇表,并修改标注器逻辑:
# 加载nlp模型后添加以下代码 # 为词汇表注册自定义POS标签 nlp.vocab.strings.add('UNM') UNM_POS = nlp.vocab.strings['UNM'] # 修改标注器的__call__方法 def __call__(self, doc): for token in doc: if token.text in self.keywords: token.pos = UNM_POS # 直接设置内置pos属性 token.tag_ = 'UNM' # 同步设置tag_(可选,保持标签一致性) return doc
修改后即可直接通过token.pos_获取自定义的UNM标签。
内容的提问来源于stack exchange,提问作者Douglas
相关产品推荐
相关产品推荐

