使用规则的方法实现NER

前置知识:NER 命名实体识别,re正则表达式,jieba分词(只描述一种思想,代码并不复杂,这些前置知识在代码实现的时候会进行解读)    #  最后有未注释总代码可直接复制  #

本次实现的主要功能

实现一个使用规则来识别一句话中的实体

识别这段文本“山东省齐鲁工业大学,坐落于山东省济南市,拥有多个校区.山东省济南大学,同样也坐落于山东省济南市.他们都是非常棒的大学”

返回一个存放两个大学名称的列表['山东省齐鲁工业大学','山东省济南大学']

主要分为两部分实现:1.设定一个领域字典   2.根据词性分词  3.设定正则表达式   4.根据正则表达式输出结果   

1.导入依赖包+设定领域字典+目标文本

(领域字典就是公司实体会结束的名字)

import re
import jieba
import jieba.posseg as pseg
# 可以根据需求自行添加
org_tag = ['大学']
text = "山东省齐鲁工业大学,坐落于山东省济南市,拥有多个校区.山东省济南大学,同样也坐落于山东省济南市.他们都非常棒"

2.根据词性分词

#pseg在jieba分词中 可以根据标注词性进行分词 lcut是分词后以列表形式返回
words_flags = pseg.lcut(text)
print(f'words_flags->{words_flags}')
words, features = [], []
for word,feature in words_flags:
    #对words_flags进行解包,获取词以及对应的词性  把所有词加入words列表中
    words.append(word)
    # 如果这个词在领域词典中,就代表实体的结束,在features中标为E
    if word in org_tag:
        features.append('E')
    # ns在jieba分词中代表地名,如果这个词性是地名,就代表实体的开始,在features中标为S
    elif feature == 'ns':
        features.append('S')
    # 其他的所有在features中标为O  不是数字0是大写字母O
    else:
        features.append('O')
print(f'words->{words}')
print(f'features->{features}')
# 使用空字符把features这个列表连成字符串
labels = ''.join(features)
print(f'labels->{labels}')

输出结果:(可以对比查看一下)

words_flags->[pair('山东省', 'ns'), pair('齐鲁', 'nr'), pair('工业', 'n'), pair('大学', 'n'), pair(',', 'x'), pair('坐落于', 'v'), pair('山东省', 'ns'), pair('济南市', 'ns'), pair(',', 'x'), pair('拥有', 'v'), pair('多个', 'm'), pair('校区', 'n'), pair('.', 'x'), pair('山东省', 'ns'), pair('济南', 'ns'), pair('大学', 'n'), pair(',', 'x'), pair('同样', 'd'), pair('也', 'd'), pair('坐落于', 'v'), pair('山东省', 'ns'), pair('济南市', 'ns'), pair('.', 'x'), pair('他们', 'r'), pair('都', 'd'), pair('是', 'v'), pair('非常', 'd'), pair('棒', 'a'), pair('的', 'uj'), pair('大学', 'n')]
words->['山东省', '齐鲁', '工业', '大学', ',', '坐落于', '山东省', '济南市', ',', '拥有', '多个', '校区', '.', '山东省', '济南', '大学', ',', '同样', '也', '坐落于', '山东省', '济南市', '.', '他们', '都', '非常', '棒']
features->['S', 'O', 'O', 'E', 'O', 'O', 'S', 'S', 'O', 'O', 'O', 'O', 'O', 'S', 'S', 'E', 'O', 'O', 'O', 'O', 'S', 'S', 'O', 'O', 'O', 'O', 'O']
labels->SOOEOOSSOOOOOSSEOOOOSSOOOOO

3.设置正则表达式

这一步没有输出,具体的匹配内容以及finditer返回格式会在下一步输出中

# 我们想得到的就是 地名开头S 中间随意O 结尾为领域字典中的E
# 设置一个正则表达式 S+是S出现最少一次 O*是O出现任意次 E+是E至少出现一次
patten = re.compile('S+O*E+')
# 使用finditer 根据patten规则 匹配由SOE组成的字符串labels
# 这里的finditer 返回一个迭代器,每次迭代都会返回一个匹配对象 其中包含起始和结束索引
finall_labels = re.finditer(patten, labels)

4.迭代正则的匹配内容,并处理为最终结果

# 定义空列表存储最终结果
list1= []
for ne in finall_labels:
    print(ne)
    # 获取匹配对象中的 起始和结束索引
    start = ne.start()
    end = ne.end()
    print(f'start->{start}')
    print(f'end->{end}')
    # 根据索引来对列表words切片 获取结果 并使用join转为字符串
    print(''.join(words[start: end]))
    #将结果加入list1中
    list1.append(''.join(words[start: end]))
print(f'最终结果->{list1}')

输出结果:可以看到for每次迭代finditer的返回结果,其中的span就是起始和结束索引,使用 .start以及.end就可以获取   并且获取到的结束索引要后一位(ex:匹配索引为0,1,2,3   返回的起始和结束索引就是0,4)这样在后续切片也是左闭右开,非常银性哈

<re.Match object; span=(0, 4), match='SOOE'>
start->0
end->4
山东省齐鲁工业大学
<re.Match object; span=(13, 16), match='SSE'>
start->13
end->16
山东省济南大学
最终结果->['山东省齐鲁工业大学', '山东省济南大学']

纯净代码纯享版(可以直接复制使用没有多余的输出和注释)

# coding: utf-8
import re
import jieba
import jieba.posseg as pseg

org_tag = ['大学']
text = "山东省齐鲁工业大学,坐落于山东省济南市,拥有多个校区.山东省济南大学,同样也坐落于山东省济南市.他们都非常棒"

words_flags = pseg.lcut(text)
words, features = [], []
for word,feature in words_flags:
    words.append(word)
    if word in org_tag:
        features.append('E')
    elif feature == 'ns':
        features.append('S')
    else:
        features.append('O')
labels = ''.join(features)
patten = re.compile('S+O*E+')
finall_labels = re.finditer(patten, labels)
list1= []
for ne in finall_labels:
    start = ne.start()
    end = ne.end()
    list1.append(''.join(words[start: end]))
print(f'最终结果->{list1}')

之后还会有主流的BiLSTM+CRF,敬请期待

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值