Python中.ann转.json工具及NER/RE模型索引、关系问题咨询
解决.ann转JSON用于NER/RE训练的方案
一、推荐的Python工具/库
- bratlib:专门适配brat标注格式(.ann/.txt)的库,原生支持实体与关系的解析,能快速转换成适配模型训练的JSON结构。示例代码:
from bratlib.data import Corpus import json # 加载brat数据集所在目录 corpus = Corpus('/path/to/your/brat/data') output_json = [] for doc in corpus.documents: doc_item = { "text": doc.text, "entities": [ { "id": ent.id, "start": ent.start, "end": ent.end, "type": ent.type, "text": ent.text } for ent in doc.entities ], "relations": [ { "id": rel.id, "type": rel.type, "head_entity_id": rel.head.id, "tail_entity_id": rel.tail.id } for rel in doc.relations ] } output_json.append(doc_item) # 保存为目标JSON文件 with open('ner_re_data.json', 'w', encoding='utf-8') as f: json.dump(output_json, f, indent=2, ensure_ascii=False) - pyconll:如果已有.conll格式文件辅助,可以结合.conll与.ann的解析结果对齐索引,适配复杂标注场景。
二、Spacy转换相关疑问解答
1. 实体索引差异大的原因
Spacy会对文本做自动分词、空格规范化(比如合并连续空格、统一换行符格式),导致原始.ann文件基于原始文本的字符索引,和Spacy预处理后内部维护的索引体系不匹配。解决方式:
- 直接用bratlib读取原始字符索引,跳过Spacy的预处理干扰;
- 若必须依赖Spacy,可通过
char_span方法将原始字符索引映射到Spacy的Doc对象中,示例:import spacy nlp = spacy.load("en_core_web_sm") raw_text = open('your_text.txt', encoding='utf-8').read() doc = nlp(raw_text) # 假设ann中实体的原始索引是start=12, end=18 span = doc.char_span(12, 18, label='PERSON') # 如需保留原始索引,手动存入结果即可
2. 嵌入关系信息到同一份JSON
Spacy默认的Doc对象不存储关系标注,但可以手动解析.ann中的关系数据,再与Spacy识别的实体通过原始字符索引/实体ID匹配关联,最终输出包含entities和relations字段的JSON,结构可参考:
{ "text": "Alice works at BobTech.", "entities": [ {"id": "T1", "start": 0, "end": 5, "type": "Person", "text": "Alice"}, {"id": "T2", "start": 15, "end": 22, "type": "Organization", "text": "BobTech"} ], "relations": [ {"id": "R1", "type": "Works_At", "head": "T1", "tail": "T2"} ] }
三、实体索引计算逻辑说明
.ann文件中的实体索引是基于原始.txt文件的字符位置(从0开始计数,包含所有空格、换行符),比如T1 Person 0 5 John表示原始文本中第0到第5位字符(左闭右开,不包含第5位)对应内容为"John",实体类型是Person。自行编写转换函数时需注意:
- 读取.txt文件时保留原始字符格式,不要自动去除换行或空格;
- 多段文本的索引是连续的,换行符算单个字符。
内容的提问来源于stack exchange,提问作者Pierpaolo Goffredo
相关产品推荐
相关产品推荐

