如何用spaCy和Python提取带B/I/O标记的b-per类NER标签?
问题描述
查阅spaCy文档后尝试用span的labels_属性提取NER标签,但实际返回的是POS标签(如NOUN、DET)而非NER标签。需要生成BIO格式的标记:
- NER span的第一个token标记为
B-<NER类型>(如B-per代表人物实体开头) - NER span的后续token标记为
I-<NER类型> - 非NER token标记为
O
目前使用的代码如下,但ent.label_返回POS标签:
for idx, doc in enumerate(train_docs): for ent in doc.ents: ner_structured_docs.append([idx, ent.text,ent.label_])
解决方案
1. 修正模型加载问题
spaCy中doc.ents里的ent.label_本身就是NER标签,返回POS标签的核心原因是你加载的模型没有包含NER组件,或是使用了空白模型/仅加载词性标注组件的模型。
解决方式:使用带有NER功能的预训练模型,比如英文的en_core_web_sm、中文的zh_core_web_sm,加载示例:
import spacy nlp = spacy.load("en_core_web_sm") # 替换为对应语言的预训练模型 # 确保train_docs是经过该nlp处理后的Doc对象 train_docs = list(nlp.pipe(your_raw_texts))
如果是自定义训练的模型,需确认训练时包含NER任务,且模型保存加载流程正常。
2. 生成BIO格式标记代码
要实现BIO标记,需要遍历每个token并判断其是否属于实体、是实体的开头还是中间部分,代码示例:
# 可选:映射spaCy的NER标签到你需要的简写(比如PERSON→per) label_mapping = { "PERSON": "per", "ORG": "org", "GPE": "loc", "DATE": "date", # 根据需求添加更多映射 } ner_structured_docs = [] for doc_idx, doc in enumerate(train_docs): # 先记录每个token对应的实体标签 token_ent_tags = {} for ent in doc.ents: # 获取实体对应的简写标签,没有映射则用原标签小写 ner_label = label_mapping.get(ent.label_, ent.label_.lower()) for token_idx in range(ent.start, ent.end): # 第一个token标记为B,后续为I tag_prefix = "B" if token_idx == ent.start else "I" token_ent_tags[token_idx] = f"{tag_prefix}-{ner_label}" # 遍历每个token生成最终标记 for token_idx, token in enumerate(doc): # 非实体token标记为O final_tag = token_ent_tags.get(token_idx, "O") ner_structured_docs.append([doc_idx, token.text, final_tag])
代码说明
- 先遍历所有实体,为每个实体包含的token分配B/I标签
- 再遍历每个token,存在实体标记则使用对应标签,否则标记为
O - 可通过
label_mapping将spaCy的标准NER标签(如PERSON)转换为你需要的简写(如per)
内容的提问来源于stack exchange,提问作者GRH
相关产品推荐
相关产品推荐

