什么是命名实体识别:
命名实体识别(Named Entity Recognition,简称NER),又称作“专名识别,就是从文本中提取出具有特定意义的实体,主要包括人名,地名,专有名字等等。
命名实体识别应用场景:
命名实体识别经常用来做关系抽取、事件抽取、知识图谱、信息提取、问答系统、句法分析、机器翻译等诸多NLP任务的基础,被广泛应用在自然语言处理领域。
对于命名实体我们一般有三种标标注方式:
一、BIO 三位标注 (B-begin,I-inside,O-outside):
注:X是我们想要标注的实体
(1)B_X:名词短语的开头
(2)I_X:名词短语的中间
(3)O:不是名词短语
二、BMES 四位序列标注法:
(1)B_X表示一个词的词首位值
(2)M_X表示一个词的中间位置
(3)E_X表示一个词的末尾位置
(4)S_X表示一个单独的字词。
三、BIOES (B-begin,I-inside,O-outside,E-end,S-single):
(1)B_X 表示开始
(2)I_X表示内部
(3)O_X表示非实体
(4)E_X实体尾部
(5)S_X表示该词本身就是一个实体
四、三种方式的优点和缺点
BIOES是我们目前最常用的命名实体识别。以前常用BIO,后来由于BIOES比较好,就改用了BIOES,因为BIOES有一个结尾的边界,对模型有很好的识别帮助。结尾边界就是E_X。而BIO没有,所以增加了模型的可识别程度。
接下来我会最常用的BIOES来进行代码复现:
data = [
{"text": "浙商银行企业信贷部叶老桂博士则从另一个角度对五道门槛进行了解读。叶老桂认为,对目前国内商业银行而言,",
"label": {"name": {"叶老桂": [[9, 11]]}, "company": {"浙商银行": [[0, 3]]}}},
{"text": "生生不息CSOL生化狂潮让你填弹狂扫", "label": {"game": {"CSOL": [[4, 7]]}}},
{"text": "那不勒斯vs锡耶纳以及桑普vs热那亚之上呢?",
"label": {"organization": {"那不勒斯": [[0, 3]], "锡耶纳": [[6, 8]], "桑普": [[11, 12]], "热那亚": [[15, 17]]}}},
{"text": "加勒比海盗3:世界尽头》的去年同期成绩死死甩在身后,后者则即将赶超《变形金刚》,",
"label": {"movie": {"加勒比海盗3:世界尽头》": [[0, 11]], "《变形金刚》": [[33, 38]]}}},
{"text": "布鲁京斯研究所桑顿中国中心研究部主任李成说,东亚的和平与安全,是美国的“核心利益”之一。",
"label": {"address": {"美国": [[32, 33]]}, "organization": {"布鲁京斯研究所桑顿中国中心": [[0, 12]]}, "name": {"李成": [[18, 19]]},
"position": {"研究部主任": [[13, 17]]}}},
{"text": "目前主赞助商暂时空缺,他们的球衣上印的是“unicef”(联合国儿童基金会),是公益性质的广告;",
"label": {"organization": {"unicef": [[21, 26]], "联合国儿童基金会": [[29, 36]]}}},
{"text": "此数据换算成亚洲盘罗马客场可让平半低水。", "label": {"organization": {"罗马": [[9, 10]]}}},
{"text": "你们是最棒的!#英雄联盟d学sanchez创作的原声王", "label": {"game": {"英雄联盟": [[8, 11]]}}},
{"text": "除了吴湖帆时现精彩,吴待秋、吴子深、冯超然已然归入二三流了,",
"label": {"name": {"吴湖帆": [[2, 4]], "吴待秋": [[10, 12]], "吴子深": [[14, 16]], "冯超然": [[18, 20]]}}},
{"text": "在豪门被多线作战拖累时,正是他们悄悄追赶上来的大好时机。重新找回全队的凝聚力是拉科赢球的资本。", "label": {"organization": {"拉科": [[39, 40]]}}}
]
# 导包
import numpy as np
# 设置一个最后带标签文本的存储路径
target_path = 'all_res.txt'
# 循环我们的每一条数据
for c in data:
values = list(c.values())
print(values)
# 取出我们的句子
sentence = values[0]
# 先取出和句子同等长度的['o']
sentence_length = ['o'] * len(values[0])
# values[1]是一个大集合,遍历这个集合,取出每一个键,然后生成开始中间和结束标签
for term in values[1]:
label_str_start = 'B_' + term
label_str_other = 'I_' + term
label_str_end = 'E_' + term
label_str_one = 'S_' + term
# 取出每个集合中对应关键字的位置下标
for i in list(values[1][term].values()):
sentence_word_wei = i[0]
# 然后把下标生成一个范围
sentence_word_wei = np.arange(sentence_word_wei[0], sentence_word_wei[1] + 1, 1).tolist()
# print(sentence_word_wei)
# 根据位置范围可以判断关键词的 起始 中间 和 结束位置的下标
start_pos = sentence_word_wei[0]
end_pos = sentence_word_wei[-1]
other_pos = sentence_word_wei[1:]
# 这个是针对只有一个关键字的情况用'S_'+term
if len(sentence_word_wei) == 1:
# print('YES')
sentence_length[start_pos] = label_str_one
# print(sentence_length)
# 不是一个词的情况
else:
# 起始值设置成B
sentence_length[start_pos] = label_str_start
for i in other_pos:
sentence_length[i] = label_str_other
# print(sentence_length)
sentence_length[end_pos] = label_str_end
# 输出每一话对应标号的关键词
print(sentence_length)
target = open(target_path, 'a', encoding='utf-8')
# 把我们的句子换成一个列表方便字符串相加
word_list = list(sentence)
print(word_list)
count = 0
# 根据句子的长度设置一个循环
for i in range(len(sentence)):
# 取出句子和句子对应位置的标签进行相加
word_ = word_list[i] + '\t' + sentence_length[i] + '\n'
count += 1
if count == len(sentence):
word_ = word_ + '\n'
# 写入文件
target.write(word_)
else:
target.write(word_)