命名实体的识别

  大家好,今天跟大家介绍一下基于pyltp做中文文本中命名实体的识别。基于词典来介绍一下整个流程,首先跟大家介绍一下理论知识以方便大家理解,最后附上完整代码供大家参考学习。

  1. 什么是命名实体的识别
  2. 基于词典与统计的算法

一、认识命名实体识别过程
1、什么是命名实体的识别
  命名实体识别(Named Entity Recognition,简称NER),又称作“专名识别”,是自然语言处理中的一项基础任务,应用范围非常广泛。命名实体一般指的是文本中具有特定意义或者指代性强的实体,通常包括 人名、地名、机构名、日期时间、专有名词等。通常包括两部分:
  实体的边界识别。
  确定实体的类型(人名、地名、机构名或其他。   NER系统就是从非结构化的输入文本中抽取出上述实体,并且可以按照业务需求识别出更多类别的实体,比如产品名称、型号、价格等。因此实体这个概念可以很广,只要是业务需要的特殊文本片段都可以称为实体。
  学术上NER所涉及的命名实体一般包括3大类(实体类,时间类,数字类)和7小类(人名、地名、组织机构名、时间、日期、货币、百分比)。实际应用中,NER模型通常只要识别出人名、地名、组织机构名、日期时间即可,一些系统还会给出专有名词结果(比如缩写、会议名、产品名等)。货币、百分比等数字类实体可通过正则搞定。另外,在一些应用场景下会给出特定领域内的实体,如书名、歌曲名、期刊名等。
2、解决方案
  命名实体识别(NER)一直是NLP领域中的研究热点,从早期基于词典和规则的方法,到传统机器学习的方法,到近年来基于深度学习的方法,命名实体识别(NER)研究进展的大概趋势大致如下图所示:
命名实体的识别_第1张图片
3、分词架构及专名词典
  命名实体的识别中遇到各种各样的困难,人们也提出来很多解决方案。人们根据各种不同的分词架构,期望通过分词架构的设计或者引入外部资源(用户自定义的含有专有名词的词典)来提高命名实体的识别精度或者减小命名实体识别对整体分词结果的干扰。分词系统的简单架构如下图所示:
命名实体的识别_第2张图片
  上述架构的特点,是将分词器针对于不同领域做了优化,不同领域的文本可以使用本领域内专门的外部词典进行识别。专业化的戏分势必带来更高的识别精度,这种策略针对领域专属的专名往往能够达到更好地分词效果。其中一种架构图如下所示:
命名实体的识别_第3张图片
二、算法策略:
基于词典与统计相结合
  有关外部词典的引入之前文章也已经介绍过了,见文章:pyltp引入外部词典。
现讲从文章TXT文章中读取命名实体以及将其结果保存至TXT文件:参考此文章:文件操作。
  那么至此就将自己所写的有关命名实体识别的代码从文件打开到外部词典的引用最终将识别的结果保存至TXT文件中,代码示例如下:

# coding=UTF-8
#打开需要命名实体识别的文本
with open(r'E:\\Python\\Pytext\\平凡的世界.txt', encoding="UTF-8", errors='ignore') as file_object:
    sss = file_object.read()
#分词
import os
LTP_DATA_DIR = 'E:\Python\pyltp\ltp\ltp\ltp_data'  # ltp模型目录的路径
cws_model_path = os.path.join(LTP_DATA_DIR, 'cws.model')  # 分词模型路径,模型名称为`cws.model`
lexicon_path = os.path.join(LTP_DATA_DIR, 'E:\Python\pyltp\ltp\ltp\ltp_data\实体名词.txt')  # 参数 是自定义词典的文件路径
from pyltp import Segmentor
segmentor = Segmentor()  # 初始化实例
segmentor.load_with_lexicon(cws_model_path, lexicon_path)
words = segmentor.segment(sss)  # 分词
words_list = list(words)   #words_list列表保存着分词的结果
segmentor.release()  # 释放模型

#词性标注
import os
LTP_DATA_DIR = 'E:\Python\pyltp\ltp\ltp\ltp_data'  # ltp模型目录的路径
pos_model_path = os.path.join(LTP_DATA_DIR, 'pos.model')  # 词性标注模型路径,模型名称为`pos.model`
from pyltp import Postagger
postagger = Postagger()  # 初始化实例
postagger.load(pos_model_path)  # 加载模型
postags = postagger.postag(words)  # 词性标注
postags_list = list(postags)  #postags_list保存着词性标注的结果
postagger.release()  # 释放模型

#命名实体识别
import os
LTP_DATA_DIR = 'E:\Python\pyltp\ltp\ltp\ltp_data'  # ltp模型目录的路径
ner_model_path = os.path.join(LTP_DATA_DIR, 'ner.model')  # 命名实体识别模型路径,模型名称为`pos.model`
from pyltp import NamedEntityRecognizer
recognizer = NamedEntityRecognizer()  # 初始化实例
recognizer.load(ner_model_path)  # 加载模型
netags = recognizer.recognize(words, postags)  # 命名实体识别
netags_list = list(netags)  #netags_list保存着命名实体识别的结果
recognizer.release()  # 释放模型

#去除非命名实体
a = len(words_list)
words_list_1=[]
postags_list_1=[]
netags_list_1=[]
i = 0
while i < a:
    if netags_list[i] != 'O':
        words_list_1.append(words_list[i])
        postags_list_1.append(postags_list[i])
        netags_list_1.append(netags_list[i])
    i += 1


a1 = len(words_list_1)
#提取机构名
i = 0
orignizations=[]
while i<a1:
    if netags_list_1[i] == 'S-Ni':
        orignizations.append(words_list_1[i])
    elif netags_list_1[i] == 'B-Ni':
        temp_s = ''
        temp_s += words_list_1[i]
        j = i+1
        while j<a1 and (netags_list_1[j]=='I-Ni' or netags_list_1[j]=='E-Ni'):
            temp_s += words_list_1[j]
            j += 1
        orignizations.append(temp_s)
    i += 1
#删除重复出现的机构名
orignizations_1  = set(orignizations)
orignizations_2 = list(orignizations_1)
f_4=open('E:\\Python\\Pytext\\orignizations.txt','w', encoding='UTF-8',errors='ignore')
for orignization in orignizations_2:
    f_4.write(orignization+'\r\n')

#提取地名
i = 0
places=[]
while i<a1:
    if netags_list_1[i] == 'S-Ns':
        places.append(words_list_1[i])
    elif netags_list_1[i] == 'B-Ns':
        temp_s = ''
        temp_s += words_list_1[i]
        j = i+1
        while j<a1 and (netags_list_1[j]=='I-Ns' or netags_list_1[j]=='E-Ns'):
            temp_s += words_list_1[j]
            j += 1
        places.append(temp_s)
    i += 1
#删除重复出现的地名
places_1 = set(places)
places_2 = list(places_1)
f_5=open('E:\\Python\\Pytext\\places.txt','w', encoding='UTF-8',errors='ignore')
for place in places_2:
    f_5.write(place+'\r\n')

#设计一些规则去除一些不符合要求的实体
places_len2 = len(places_2)
j = 0
places_3 = []  #places_3存在最终的地名
while j <places_len2:
    flag = 0
    len_2 = len(places_2[j])
    if len_2 <= 1 or len_2 >3:
        flag = 1
    else:
        i = 0
        len_2 = len(places_2[j])
        while i < len_2:
            if places_2[j][i] =='。' or places_2[j][i]=='.' or places_2[j][i] == '\n':
                flag = 1
            if places_2[j][i]>='a' and places_2[j][i]<='z':
                flag = 1
            if places_2[j][i]>='0' and places_2[j][i]<='9':
                flag = 1
            i += 1
    if flag == 0:
        places_3.append(places_2[j])
    j += 1
f_72=open('E:\\Python\\Pytext\\place_2.txt','w', encoding='UTF-8',errors='ignore')
for place3 in places_3:
    f_72.write(place3+'\n')

#提取人名
i = 0
names=[]
while i<a1:
    if netags_list_1[i] == 'S-Nh':
        names.append(words_list_1[i])
    elif netags_list_1[i] == 'B-Nh':
        temp_s3 = ''
        temp_s3 += words_list_1[i]
        j = i+1
        while (j<a1) and (netags_list_1[j]=='I-Nh' or netags_list_1[j]=='E-Nh'):
            temp_s3 += words_list_1[j]
            j += 1
        names.append(temp_s3)
    i += 1
#去除重复的人名
names_1 = set(names)
names_2 = list(names_1)
f_6=open('E:\\Python\\Pytext\\mingzi.txt','w', encoding='UTF-8',errors='ignore')
for name in names_2:
    f_6.write(name+'\n')
#设计一些规则去除一些不符合要求的实体
names_len2 = len(names_2)
j = 0
names_3 = []
while j <names_len2:
    flag = 0
    len_2 = len(names_2[j])
    if len_2 <= 1 or len_2 >3:
        flag = 1
    else:
        i = 0
        len_2 = len(names_2[j])
        while i < len_2:
            if names_2[j][i] =='。' or names_2[j][i]=='.' or names_2[j][i] == '\n':
                flag = 1
            if names_2[j][i]>='a' and names_2[j][i]<='z':
                flag = 1
            if names_2[j][i]>='0' and names_2[j][i]<='9':
                flag = 1
            i += 1
    if flag == 0:
        names_3.append(names_2[j])
    j += 1
f_7=open('E:\\Python\\Pytext\\mingzi_2.txt','w', encoding='UTF-8',errors='ignore')
for name3 in names_3:
    f_7.write(name3+'\n')

#将三个列表整合到一个字典中,写入文件
shiti = {}
for name in names_3:
    shiti[name] = '人名'
for place in places_3:
    shiti[place] = '地名'
for orignization in orignizations_2:
    shiti[orignization] = '机构名'

f_shiti=open('E:\\Python\\Pytext\\2.txt','w', encoding='UTF-8',errors='ignore')
for key, value in shiti.items():
    f_shiti.write(key+ '\t' + value + '\n')

  提醒一下,注意更改模型文件,以及自己结合自己的所需进行更外部词典来改代码,也可以在此基础上进行撰写自己的代码。
  最后,祝大家生活愉快,倘若对您有所帮助,可以点赞哦。
参考博客:
原文链接:https://blog.csdn.net/Mr_Robert/article/details/88756398

你可能感兴趣的:(自然语言处理)