doccano標註後的序列標註任務資料轉錄為BIO形式
阿新 • • 發佈:2021-01-01
掃碼關注公眾號“自然語言處理與演算法”,帶你搞NLP~
今兒是2020年12月31日,本年度最後一更,盆友們,2021再見!繼續努力鴨~
doccano是一個開源的語料標註工具,其可以用來標註實體識別訓練語料。但是標註之後的資料是不能直接作為訓練資料的,還需要將其轉錄一下,下面以轉錄為BIO為例。
1 doccano標註之後的資料格式(json)
{"id": 4, "text": "?生益科技主要從事覆銅板製造與銷售業務,銷售收入佔到公司總收入的81.52%。", "meta" : {}, "annotation_approver": null, "labels": [[1, 5, "ORG"], [32, 38, "NUM"]]}
{"id": 6, "text": "目前,益科技,已是覆銅板的龍頭企業。早在公司2018 年年報,生益科技硬質覆銅板銷售總額全球排名第二。", "meta": {}, "annotation_approver": null, "labels" : [[31, 35, "ORG"], [22, 27, "NUM"], [3, 6, "ORG"], [20, 22, "ORG"]]}
{"id": 9, "text": "專注高頻覆銅板的南通專案一期產能為100w平米/年,現逐步投產。", "meta": {}, "annotation_approver": null, "labels": [[17, 21, "NUM"]]}
{ "id": 10, "text": "?獲得NOKIA、華為、中興、浪潮、格力、國星光電等客戶的認可。", "meta": {}, "annotation_approver": null, "labels": [[3, 8, "ORG"], [9, 11, "ORG"], [12, 14, "ORG"], [15, 17, "ORG"], [18, 20, "ORG"], [21, 25, "ORG"]]}
{"id": 11, "text": "③業績符合預期,產品未來看點足", "meta": {}, "annotation_approver": null, "labels": [[1, 3, "PRO"], [5, 7, "TAP"]]}
需要注意的是以上並不是標準的json格式,所以直接從doccano系統裡下載下來的json是不能用python直接載入的。
標準的json檔案格式如下:
[
{''''},
{'''''},
{'''''}
]
轉換程式碼如下:
def generate_json():
'''將標註系統下載下來的檔案轉換為標準json格式'''
f1 = open('out.json', 'w', encoding='utf-8')
f1.write("[")
with open('in.json', 'r', encoding='utf-8')as f2:
lines = f2.readlines()
k = len(lines)
i = 0
while i < k-2:
f1.write(lines[i].strip() + ',\n')
i += 1
f1.write(lines[i].strip() + '\n')
f1.write(']')
f1.close()
轉換為標準格式後可以直接載入,然後將其中的資料轉錄為BIO形式。
2.轉錄為BIO
轉錄程式碼如下:
import json
def tranfer2bio():
'''
將json檔案中的資料轉錄為BIO形式,儲存規則可以在43行修改
:return:
'''
f1 = open('./train.txt', 'w', encoding='utf-8')
with open("./1.json", 'r', encoding='utf-8') as inf:
load = json.load(inf)
for i in range(len(load)):
labels = load[i]['labels']
text = load[i]['text']
tags = ['O'] * len(text)
for j in range(len(labels)):
label = labels[j]
#print(label)
tags[label[0]] = 'B-' + str(label[2])
k = label[0]+1
while k < label[1]:
tags[k] = 'I-' + str(label[2])
k += 1
print(tags)
for word, tag in zip(text, tags):
f1.write(word + '\t' + tag + '\n')
f1.write("\n")
#tranfer2bio()
3.根據BIO序列提取實體
模型預測出對應文字的BIO序列後,如何根據序列提取實體呢?這個問題有很多解決辦法。博主這裡給出一個開源通用的解決方法[1]。
思路1:遇到B則前面存在的實體,進行一次儲存。多個i粘連一塊兒也可能被認為是一個實體。錯誤的情況是B識別成i了。對於類別判斷失誤,粘連的實體取眾數。
#標籤轉錄BIO格式
string="我是李明,我愛中國,我來自呼和浩特"
predict=["o","o","i-per","i-per","o","o","o","b-loc","i-loc","o","o","o","o","b-per","i-loc","i-loc","i-loc"]
item = {"string": string, "entities": []}
entity_name = ""
flag=[]
visit=False
for char, tag in zip(string, predict):
if tag[0] == "b":
if entity_name!="":
x=dict((a,flag.count(a)) for a in flag)
y=[k for k,v in x.items() if max(x.values())==v]
item["entities"].append({"word": entity_name,"type": y[0]})
flag.clear()
entity_name=""
entity_name += char
flag.append(tag[2:])
elif tag[0]=="i":
entity_name += char
flag.append(tag[2:])
else:
if entity_name!="":
x=dict((a,flag.count(a)) for a in flag)
y=[k for k,v in x.items() if max(x.values())==v]
item["entities"].append({"word": entity_name,"type": y[0]})
flag.clear()
flag.clear()
entity_name=""
if entity_name!="":
x=dict((a,flag.count(a)) for a in flag)
y=[k for k,v in x.items() if max(x.values())==v]
item["entities"].append({"word": entity_name,"type": y[0]})
print(item)
{'string': '我是李明,我愛中國,我來自呼和浩特', 'entities': [{'word': '李明', 'type': 'per'}, {'word': '中國', 'type': 'loc'}, {'word': '呼和浩特', 'type': 'loc'}]}
思路2:只取B開頭的實體,其它的不要。同樣類別也是取眾數。
#標籤轉錄BIO格式
string="我是李明,我愛中國,我來自呼和浩特"
predict=["o","o","i-per","i-per","o","o","o","b-loc","i-loc","o","o","o","o","b-per","i-loc","i-loc","i-loc"]
item = {"string": string, "entities": []}
entity_name = ""
flag=[]
visit=False
for char, tag in zip(string, tags):
if tag[0] == "b":
if entity_name!="":
x=dict((a,flag.count(a)) for a in flag)
y=[k for k,v in x.items() if max(x.values())==v]
item["entities"].append({"word": entity_name,"type": y[0]})
flag.clear()
entity_name=""
visit=True
entity_name += char
flag.append(tag[2:])
elif tag[0]=="i" and visit:
entity_name += char
flag.append(tag[2:])
else:
if entity_name!="":
x=dict((a,flag.count(a)) for a in flag)
y=[k for k,v in x.items() if max(x.values())==v]
item["entities"].append({"word": entity_name,"type": y[0]})
flag.clear()
flag.clear()
visit=False
entity_name=""
if entity_name!="":
x=dict((a,flag.count(a)) for a in flag)
y=[k for k,v in x.items() if max(x.values())==v]
item["entities"].append({"word": entity_name,"type": y[0]})
print(item)
{'string': '我是李明,我愛中國,我來自呼和浩特', 'entities': [{'word': '中國', 'type': 'loc'}, {'word': '呼和浩特', 'type': 'loc'}]}
2020年12月31日 於上海
參考文獻
[1]BIO序列提取實體(NER命名實體識別).https://blog.csdn.net/hqh131360239/article/details/107764716