文章目录
简介
BIO命名实体标注格式如下:
(数据太多行,只展示一部分数据)
可 O
见 O
...
宋 B-PER
神 I-PER
宗 I-PER
时 O
, O
官 O
拜 O
礼 B-ORG
部 I-ORG
郎 O
杨 B-PER
次 I-PER
公 I-PER
...
上述BIO形式数据,通常使用分类算法进行训练。
然而对于一些生成式的模型,无法使用上述数据集。
故本文实现转换BIO数据集为如下形式:
bash
['可见牧牛图是根据宋神宗时,官拜礼部郎杨次公的"牧牛颂"而创作的。', [('宋神宗', 'PER'), ('礼部', 'ORG'), ('杨次公', 'PER')]]
提供了列表格式的数据,便于用户修改与自定义转换数据格式。
代码实现
python
file = 'data/test.txt'
with open(file, 'r', encoding='utf-8') as f:
texts = f.read().rstrip()
data = texts.split('\n\n')
total = []
for i in range(len(data)):
line = data[i].split('\n')
start, end = 0, 0
offsets = [] # 存储每个实体的起始下标位置和结束下标位置
texts = []
labels = []
for idx, item in enumerate(line):
word, label = item.split(' ')
texts.append(word)
labels.append(label)
if label[0] == 'B':
if start and end:
offsets.append((start, end))
start, end = idx, 0
if label == 'O':
if start and not end:
end = idx
if start and end:
offsets.append((start, end))
texts = ''.join(texts)
ents = [
(texts[start:end], labels[start][2:])
for start, end in offsets
]
total.append([
texts,
ents
])
for line in total:
print(line)
上述代码的offsets
存储的是实体的开始下标和结束下标。若您希望得到实体的下标,请关注offsets
变量。
实验
输入:file = 'data/test.txt'
为 BIO数据集的文件路径;
输出:
bash
['我们变而以书会友,以书结缘,把欧美、港台流行的食品类图谱、画册、工具书汇集一堂。', [('美', 'LOC'), ('台', 'LOC')]]
['为了跟踪国际最新食品工艺、流行趋势,大量搜集海外专业书刊资料是提高技艺的捷径。', []]
['其中线装古籍逾千册;民国出版物几百种;珍本四册、稀见本四百余册,出版时间跨越三百余年。', []]
...
扩展应用
借助于上述代码将BIO数据,转换为下述格式(该格式为Deepke的命名实体识别格式):
python
{"text": "我们变而以书会友,以书结缘,把欧美、港台流行的食品类图谱、画册、工具书汇集一堂。", "entity": [{"entity": "美", "entity_type": "LOC"}, {"entity": "台", "entity_type": "LOC"}]}
代码
实现从文件到文件的转换,方便使用;
bash
import json
def convert(input_file, output_file):
def _iter_data():
with open(input_file, 'r', encoding='utf-8') as f:
texts = f.read().rstrip()
data = texts.split('\n\n')
for i in range(len(data)):
line = data[i].split('\n')
start, end = 0, 0
offsets = [] # 存储每个实体的起始下标位置和结束下标位置
texts = []
labels = []
for idx, item in enumerate(line):
word, label = item.split(' ')
texts.append(word)
labels.append(label)
if label[0] == 'B':
if start and end:
offsets.append((start, end))
start, end = idx, 0
if label == 'O':
if start and not end:
end = idx
if start and end:
offsets.append((start, end))
texts = ''.join(texts)
ents = [
(texts[start:end], labels[start][2:])
for start, end in offsets
]
yield {
"text": texts,
"entity": [
{'entity': entity, 'entity_type': entity_type}
for entity, entity_type in ents
]
}
with open(output_file, 'w', encoding='utf-8') as f:
for item in _iter_data():
f.write(json.dumps(item, ensure_ascii=False) + '\n')
if __name__ == '__main__':
convert('data/test.txt', 'output/test.json')