序列标注一般采用两种模式BIO和BIOES
标签说明
标签方案中通常都使用一些简短的英文字符[串]来编码。
标签是打在token上的。
对于英文,token可以是一个单词(e.g. awesome),也可以是一个字符(e.g. a)。
对于中文,token可以是一个词语(分词后的结果),也可以是单个汉字字符。
为便于说明,以下都将token试作等同于字符。
标签列表如下:
B,即Begin,表示开始
I,即Intermediate,表示中间
E,即End,表示结尾
S,即Single,表示单个字符
O,即Other,表示其他,用于标记无关字符
常见标签方案
基于上面的标签列表,通过选择该列表的子集,可以得到不同的标签方案。同样的标签列表,不同的使用方法,也可以得到不同的标签方案。
以前的较为流行的标签方案有如下几种:
IOB1: 标签I用于文本块中的字符,标签O用于文本块之外的字符,标签B用于在该文本块前面接续则一个同类型的文本块情况下的第一个字符。
IOB2: 每个文本块都以标签B开始,除此之外,跟IOB1一样。
IOE1: 标签I用于独立文本块中,标签E仅用于同类型文本块连续的情况,假如有两个同类型的文本块,那么标签E会被打在第一个文本块的最后一个字符。
IOE2: 每个文本块都以标签E结尾,无论该文本块有多少个字符,除此之外,跟IOE1一样。
START/END (也叫SBEIO、IOBES): 包含了全部的5种标签,文本块由单个字符组成的时候,使用S标签来表示,由一个以上的字符组成时,首字符总是使用B标签,尾字符总是使用E标签,中间的字符使用I标签。
IO: 只使用I和O标签,显然,如果文本中有连续的同种类型实体的文本块,使用该标签方案不能够区分这种情况。
其中最常用的是IOB2、IOBS、IOBES。
现在的常用标签方案
IOB 标注法
IOB 标注法, 是 CoNLL 2003 采用的标注法, I 表示 inside, O 表示 Outside, B 表示 Begin。而标注的 label是 I-XXX 的, 表示这个字符, 在 XXX类命名实体的内部(inside)。B用于标记一个命名实体的开始。
比如:
Tom B-PER
hanks I-PER
is O
my O
name O
BIOES
这是在 IOB方法上,扩展出的一个更复杂,但更完备的标注方法。其中 B表示这个词处于一个实体的开始(Begin), I 表示内部(inside), O 表示外部(outside), E 表示这个词处于一个实体的结束为止, S 表示,这个词是自己就可以组成一个实体(Single)
BIOES 是目前最通用的命名实体标注方法。
Markup
Makeup 是 OntoNotes 使用的标注方法, 思路比较简单, XML, 比如:
ENAMEX TYPE=”ORG”>DisneyENAMEX> is a global brand .
它用标签把 命名实体框出来, 然后,在 TYPE 上, 设置相应的类型。
标注工具:
https://github.com/jiesutd/SUTDAnnotator
import re
# txt2ner_train_data turn label str into ner trainable data
# s :labeled str eg.'我来到[@1999年#YEAR*]的[@上海#LOC*]的[@东华大学#SCHOOL*]'
# save_path: ner_trainable_txt name
def str2ner_train_data(s,save_path):
ner_data = []
result_1 = re.finditer(r'\[\@', s)
result_2 = re.finditer(r'\*\]', s)
begin = []
end = []
for each in result_1:
begin.append(each.start())
for each in result_2:
end.append(each.end())
assert len(begin) == len(end)
i = 0
j = 0
while i < len(s):
if i not in begin:
ner_data.append([s[i], 0])
i = i + 1
else:
ann = s[i + 2:end[j] - 2]
entity, ner = ann.rsplit('#')
if (len(entity) == 1):
ner_data.append([entity, 'S-' + ner])
else:
if (len(entity) == 2):
ner_data.append([entity[0], 'B-' + ner])
ner_data.append([entity[1], 'E-' + ner])
else:
ner_data.append([entity[0], 'B-' + ner])
for n in range(1, len(entity) - 1):
ner_data.append([entity[n], 'I-' + ner])
ner_data.append([entity[-1], 'E-' + ner])
i = end[j]
j = j + 1
f = open(save_path, 'w', encoding='utf-8')
for each in ner_data:
f.write(each[0] + ' ' + str(each[1]))
f.write('\n')
f.close()
# txt2ner_train_data turn label str into ner trainable data
# file_path :labeled multi lines' txt eg.'我来到[@1999年#YEAR*]的[@上海#LOC*]的[@东华大学#SCHOOL*]'
# save_path: ner_trainable_txt name
def txt2ner_train_data(file_path,save_path):
fr=open(file_path,'r',encoding='utf-8')
lines=fr.readlines()
s=''
for line in lines:
line=line.replace('\n','')
line=line.replace(' ','')
s=s+line
fr.close()
str2ner_train_data(s, save_path)
if(__name__=='__main__'):
s = '我来到[@1999年#YEAR*]的[@上海#LOC*]的[@东华大学#SCHOOL*]'
save_path = 's.txt'
str2ner_train_data(s, save_path)
file_path='D:\\codes\\python_codes\\SUTDAnnotator-master\\demotext\\ChineseDemo.txt.ann'
txt2ner_train_data(file_path,'s1.txt')
YEDDA
YEDDA可以进行chunk/entity/event三种标注任务。它使用tkinter开发,当前只支持在Python2.7下运行。对外提供两种用户界面,一种是标注员界面(终端执行python YEDDA.py),一种是管理员界面(终端执行python YEDDA_Admin.py)。标注员界面用于给句子做标注,管理员界面提供针对同一文件的不同人员标注结果的对比等功能。标注界面如下图所示
其中的按钮的大致功能为Open
按钮用于打开待校对的文件。ReMap
用于将用户设置的标注快捷键更新到当前配置文件。NewMap
按钮用于将用户设置的标注快捷键保存到新的配置文件。RMOn
是打开机器自动标注功能,RMOff
是关闭机器自动标注功能。Export
到处当前标注后的文本。Quit
退出当前标注。字母A
,B
,C
,D
,E
,F
,G
分别对应右侧所列功能的快捷键,比如Location地名的快捷键为D
。Cursor
表示当前光标在文本中的为止,RMModel
指的是是否启动了机器自动标注。Map Templates
快捷键配置文件名。
YEDDA的缺点有:
(1)可标记种类数只有7种
(2)没有情感类别或分类类别的标记功能
(3)一次性将文本内容全部展示出来不利于标注者标记
(4)没有分词功能也不能使用自己的分词器
(5)没有类别预测功能
(6)只能运行在Python2.7版本下。
可改进的点有:
(1)添加类别预测展示及标注功能
(2)添加标注进度展示区
(3)添加分词功能
(4)添加实体识别功能
(5)导出时,计算本次标注后系统预测的准确率
参考资料:
https://www.cnblogs.com/bep-feijin/articles/9650898.html
https://blog.csdn.net/app_12062011/article/details/88370570
https://blog.csdn.net/u011828281/article/details/81171066
https://www.cnblogs.com/combfish/p/7830807.html
https://github.com/immense8342/YEDDA
https://zhuanlan.zhihu.com/p/64745990