1.命名实体识别

命名实体识别(Named EntitiesRecognition,NER)是自然语言处理的一个基础任务。其目的是识别语料中人名、地名、组织机构名等命名实体。

由于命名实体数量不断增加,通常不可能在词典中穷尽列出,且其构成方法具有各自的一些规律性,因而,通常把对这些词的识别从词汇形态处理(如汉语切分)任务中独立处理,称为命名实体识别。命名实体识别技术是信息抽取、信息检索、机器翻译、问答系统等多种自然语言处理技术必不可少的组成部分。

2.常见的命名实体识别方法综述

命名实体是命名实体识别的研究主体,一般包括三大类(实体类、时间类和数字类)和七小类(人名、地名、机构名、时间、日期、货币和百分比)命名实体。评判一个命名实体是否被正确识别包括两个方面:实体的边界是否正确和实体的类型是否标注正确。

命名实体识别的主要技术方法分为:基于规则和词典的方法、基于统计的方法、二者混合的方法等。

2.1基于规则和词典的方法。

基于规则的方法多采用语言学专家手工构造规则模板,选用特征包括统计信息、标点符号、关键字、指示词和方向词、位置词(如尾字)、中心词等方法,以模式和字符串相匹配为主要手段,这类系统大多依赖于知识库和词典的建立。基于规则和词典的方法是命名实体识别中最早使用的方法,一般而言,当提取的规则能比较精确地反映语言现象时,基于规则的方法性能要优于基于统计的方法。但是这些规则往往依赖于具体语言、领域和文本风格,编制过程耗时且难以涵盖所有的语言现象,特别容易产生错误,系统可移植性不好,对于不同的系统需要语言学专家重新书写规则。基于规则的方法的另外一个缺点是代价太大,存在系统建设周期长、移植性差而且需要建立不同领域知识库作为辅助以提高系统识别能力等问题。

2.2基于统计的方法。

基于统计机器学习的方法主要包括隐马尔可夫模型(HiddenMarkovMode,HMM)、最大熵(MaxmiumEntropy,ME)、支持向量机(Support VectorMachine,SVM)、条件随机场(ConditionalRandom Fields,CRF)等。

在基于统计的这四种学习方法中,最大熵模型结构紧凑,具有较好的通用性,主要缺点是训练时间长复杂性高,有时甚至导致训练代价难以承受,另外由于需要明确的归一化计算,导致开销比较大。而条件随机场为命名实体识别提供了一个特征灵活、全局最优的标注框架,但同时存在收敛速度慢、训练时间长的问题。一般说来,最大熵和支持向量机在正确率上要比隐马尔可夫模型高一些,但隐马尔可夫模型在训练和识别时的速度要快一些,主要是由于在利用 Viterbi 算法求解命名实体类别序列时的效率较高。隐马尔可夫模型更适用于一些对实时性有要求以及像信息检索这样需要处理大量文本的应用,如短文本命名实体识别。

基于统计的方法对特征选取的要求较高,需要从文本中选择对该项任务有影响的各种特征,并将这些特征加入到特征向量中。依据特定命名实体识别所面临的主要困难和所表现出的特性,考虑选择能有效反映该类实体特性的特征集合。主要做法是通过对训练语料所包含的语言信息进行统计和分析,从训练语料中挖掘出特征。有关特征可以分为具体的单词特征、上下文特征、词典及词性特征、停用词特征、核心词特征以及语义特征等。

基于统计的方法对语料库的依赖也比较大,而可以用来建设和评估命名实体识别系统的大规模通用语料库又比较少。

2.3混合方法。

自然语言处理并不完全是一个随机过程,单独使用基于统计的方法使状态搜索空间非常庞大,必须借助规则知识提前进行过滤修剪处理。目前几乎没有单纯使用统计模型而不使用规则知识的命名实体识别系统,在很多情况下是使用混合方法:

  • 统计学习方法之间或内部层叠融合。
  • 规则、词典和机器学习方法之间的融合,其核心是融合方法技术。在基于统计的学习方法中引入部分规则,将机器学习和人工知识结合起来。
  • 将各类模型、算法结合起来,将前一级模型的结果作为下一级的训练数据,并用这些训练数据对模型进行训练,得到下一级模型。

3. 命名实体识别的一般流程

如下图所示,一般的命名实体流程主要分为四个步骤:

  • 对需要进行提取的文本语料进行分词;
  • 获取需要识别的领域标签,并对分词结果进行标签标注;
  • 对标签标注的分词进行抽取;
  • 将抽取的分词组成需要的领域的命名实体。

4.使用jieba进行命名实体提取

import jieba
import jieba.analyse
import jieba.posseg as posg#使用 jieba 进行词性切分,allowPOS 指定允许的词性,这里选择名词 n 和地名 ns:
sentence=u'''上线三年就成功上市,拼多多上演了互联网企业的上市奇迹,却也放大平台上存在的诸多问题,拼多多在美国上市。'''
kw=jieba.analyse.extract_tags(sentence,topK=10,withWeight=True,allowPOS=('n','ns'))#关键词提取
for item in kw:print(item[0],item[1])print("---------------------")
# 关键词抽取
kw=jieba.analyse.textrank(sentence,topK=20,withWeight=True,allowPOS=('ns','n'))
for item in kw:print(item[0],item[1])
上市 1.437080435586
上线 0.820694551317
奇迹 0.775434839431
互联网 0.712189275429
平台 0.6244340485550001
企业 0.422177218495
美国 0.415659623166
问题 0.39635135730800003
---------------------
上市 1.0
奇迹 0.572687398431635
企业 0.5710407272273452
互联网 0.5692560484441649
上线 0.23481844682115297
美国 0.23481844682115297

5.pyhanlp 进行命名实体识别和提取。

from pyhanlp import *#进行词性切分:sentence=u'''上线三年就成功上市,拼多多上演了互联网企业的上市奇迹,却也放大平台上存在的诸多问题,拼多多在美国上市。'''
analyzer = PerceptronLexicalAnalyzer()
segs = analyzer.analyze(sentence)
arr = str(segs).split(" ")
# 定义一个函数,从得到的结果中,根据词性获取指定词性的词:def get_result(arr,ner):re_list = []for x in arr:temp = x.split("/")if(temp[1] in ner):re_list.append(temp[0])return re_listner = ['n','ns']
result = get_result(arr,ner)
print(result)
['上线', '互联网', '企业', '奇迹', '平台', '问题', '美国']

6.基于CRF的中文命名实体识别

6.1随机场

“随机场”的名字取的很玄乎,其实理解起来不难。随机场是由若干个位置组成的整体,当按照某种分布给每一个位置随机赋予一个值之后,其全体就叫做随机场。

还是举词性标注的例子。假如我们有一个十个词形成的句子需要做词性标注。这十个词每个词的词性可以在我们已知的词性集合(名词,动词……)中去选择。当我们为每个词选择完词性后,这就形成了一个随机场。

6.2马尔科夫随机场

马尔科夫随机场是随机场的特例,它假设随机场中某一个位置的赋值仅仅与和它相邻的位置的赋值有关,和与其不相邻的位置的赋值无关。

继续举十个词的句子词性标注的例子。如果我们假设所有词的词性只和它相邻的词的词性有关时,这个随机场就特化成一个马尔科夫随机场。比如第三个词的词性除了与自己本身的位置有关外,还只与第二个词和第四个词的词性有关。

6.3CRF条件随机场【马尔科夫的特例】

CRF 是马尔科夫随机场的特例,它假设马尔科夫随机场中只有 X 和 Y 两种变量,X 一般是给定的,而 Y 一般是在给定 X 的条件下我们的输出。这样马尔科夫随机场就特化成了条件随机场。

在我们十个词的句子词性标注的例子中,X 是词,Y 是词性。因此,如果我们假设它是一个马尔科夫随机场,那么它也就是一个 CRF。

对于 CRF,我们给出准确的数学语言描述:设 X 与 Y 是随机变量,P(Y|X) 是给定 X 时 Y 的条件概率分布,若随机变量 Y 构成的是一个马尔科夫随机场,则称条件概率分布 P(Y|X) 是条件随机场。

6.4 命名实体识别案例

使用人民日报1998年标注数据,进行预处理。语料库词性标记中,对应的实体词依次为 t、nr、ns、nt。对语料需要做以下处理:

  • 将语料全角字符统一转为半角;
  • 合并语料库分开标注的姓和名,例如:温/nr 家宝/nr;
  • 合并语料库中括号中的大粒度词,例如:[国家/n 环保局/n]nt;
  • 合并语料库分开标注的时间,例如:(/w 一九九七年/t 十二月/t 三十一日/t )/w。

对语料中的句子、词性,实体分类标记进行区分。标签采用“BIO”体系,即实体的第一个字为 B_,其余字为 I_,非实体字统一标记为 O。大部分情况下,标签体系越复杂,准确度也越高,但这里采用简单的 BIO 体系也能达到相当不错的效果。这里模型采用 tri-gram 形式,所以在字符列中,要在句子前后加上占位符。

import re
import sklearn_crfsuite
from sklearn_crfsuite import metrics
import joblibdir = '基于CRF的中文命名实体识别模型实现//'
class CorpusProcess(object):def __init__(self):"""初始化"""self.train_corpus_path = dir+ "1980_01rmrb.txt"self.process_corpus_path = dir + "result-rmrb.txt"self._maps = {u't': u'T',u'nr': u'PER', u'ns': u'ORG',u'nt': u'LOC'}def read_corpus_from_file(self, file_path):"""读取语料"""f = open(file_path, 'r',encoding='utf-8')lines = f.readlines()f.close()return linesdef write_corpus_to_file(self, data, file_path):"""写语料"""f = open(file_path, 'wb')f.write(data)f.close()def q_to_b(self,q_str):"""全角转半角"""b_str = ""for uchar in q_str:inside_code = ord(uchar)if inside_code == 12288:  # 全角空格直接转换inside_code = 32elif 65374 >= inside_code >= 65281:  # 全角字符(除空格)根据关系转化inside_code -= 65248b_str += chr(inside_code)return b_strdef b_to_q(self,b_str):"""半角转全角"""q_str = ""for uchar in b_str:inside_code = ord(uchar)if inside_code == 32:  # 半角空格直接转化inside_code = 12288elif 126 >= inside_code >= 32:  # 半角字符(除空格)根据关系转化inside_code += 65248q_str += chr(inside_code)return q_strdef pre_process(self):"""语料预处理 """lines = self.read_corpus_from_file(self.train_corpus_path)new_lines = []for line in lines:words = self.q_to_b(line.strip()).split(u'  ')pro_words = self.process_t(words)pro_words = self.process_nr(pro_words)pro_words = self.process_k(pro_words)new_lines.append('  '.join(pro_words[1:]))self.write_corpus_to_file(data='\n'.join(new_lines).encode('utf-8'), file_path=self.process_corpus_path)def process_k(self, words):"""处理大粒度分词,合并语料库中括号中的大粒度分词,类似:[国家/n  环保局/n]nt """pro_words = []index = 0temp = u''while True:word = words[index] if index < len(words) else u''if u'[' in word:temp += re.sub(pattern=u'/[a-zA-Z]*', repl=u'', string=word.replace(u'[', u''))elif u']' in word:w = word.split(u']')temp += re.sub(pattern=u'/[a-zA-Z]*', repl=u'', string=w[0])pro_words.append(temp+u'/'+w[1])temp = u''elif temp:temp += re.sub(pattern=u'/[a-zA-Z]*', repl=u'', string=word)elif word:pro_words.append(word)else:breakindex += 1return pro_wordsdef process_nr(self, words):""" 处理姓名,合并语料库分开标注的姓和名,类似:温/nr  家宝/nr"""pro_words = []index = 0while True:word = words[index] if index < len(words) else u''if u'/nr' in word:next_index = index + 1if next_index < len(words) and u'/nr' in words[next_index]:pro_words.append(word.replace(u'/nr', u'') + words[next_index])index = next_indexelse:pro_words.append(word)elif word:pro_words.append(word)else:breakindex += 1return pro_wordsdef process_t(self, words):"""处理时间,合并语料库分开标注的时间词,类似: (/w  一九九七年/t  十二月/t  三十一日/t  )/w   """pro_words = []index = 0temp = u''while True:word = words[index] if index < len(words) else u''if u'/t' in word:temp = temp.replace(u'/t', u'') + wordelif temp:pro_words.append(temp)pro_words.append(word)temp = u''elif word:pro_words.append(word)else:breakindex += 1return pro_wordsdef pos_to_tag(self, p):"""由词性提取标签"""t = self._maps.get(p, None)return t if t else u'O'def tag_perform(self, tag, index):"""标签使用BIO模式"""if index == 0 and tag != u'O':return u'B_{}'.format(tag)elif tag != u'O':return u'I_{}'.format(tag)else:return tagdef pos_perform(self, pos):"""去除词性携带的标签先验知识"""if pos in self._maps.keys() and pos != u't':return u'n'else:return posdef initialize(self):"""初始化 """lines = self.read_corpus_from_file(self.process_corpus_path)words_list = [line.strip().split('  ') for line in lines if line.strip()]del linesself.init_sequence(words_list)def init_sequence(self, words_list):"""初始化字序列、词性序列、标记序列 """words_seq = [[word.split(u'/')[0] for word in words] for words in words_list]pos_seq = [[word.split(u'/')[1] for word in words] for words in words_list]tag_seq = [[self.pos_to_tag(p) for p in pos] for pos in pos_seq]self.pos_seq = [[[pos_seq[index][i] for _ in range(len(words_seq[index][i]))]for i in range(len(pos_seq[index]))] for index in range(len(pos_seq))]self.tag_seq = [[[self.tag_perform(tag_seq[index][i], w) for w in range(len(words_seq[index][i]))]for i in range(len(tag_seq[index]))] for index in range(len(tag_seq))]self.pos_seq = [[u'un']+[self.pos_perform(p) for pos in pos_seq for p in pos]+[u'un'] for pos_seq in self.pos_seq]self.tag_seq = [[t for tag in tag_seq for t in tag] for tag_seq in self.tag_seq]self.word_seq = [[u'<BOS>']+[w for word in word_seq for w in word]+[u'<EOS>'] for word_seq in words_seq]   def extract_feature(self, word_grams):"""特征选取"""features, feature_list = [], []for index in range(len(word_grams)):for i in range(len(word_grams[index])):word_gram = word_grams[index][i]feature = {u'w-1': word_gram[0], u'w': word_gram[1], u'w+1': word_gram[2],u'w-1:w': word_gram[0]+word_gram[1], u'w:w+1': word_gram[1]+word_gram[2],# u'p-1': self.pos_seq[index][i], u'p': self.pos_seq[index][i+1],# u'p+1': self.pos_seq[index][i+2],# u'p-1:p': self.pos_seq[index][i]+self.pos_seq[index][i+1],# u'p:p+1': self.pos_seq[index][i+1]+self.pos_seq[index][i+2],u'bias': 1.0}feature_list.append(feature)features.append(feature_list)feature_list = []return features def segment_by_window(self, words_list=None, window=3):"""窗口切分"""words = []begin, end = 0, windowfor _ in range(1, len(words_list)):if end > len(words_list): breakwords.append(words_list[begin:end])begin = begin + 1end = end + 1return wordsdef generator(self):"""训练数据"""word_grams = [self.segment_by_window(word_list) for word_list in self.word_seq]features = self.extract_feature(word_grams)return features, self.tag_seq
class CRF_NER(object):def __init__(self):"""初始化参数"""self.algorithm = "lbfgs"self.c1 ="0.1"self.c2 = "0.1"self.max_iterations = 100self.model_path = '/root/jupyterData/jupyterLabPerject//NLP//' + "model.pkl"self.corpus = CorpusProcess()  #Corpus 实例self.corpus.pre_process()  #语料预处理self.corpus.initialize()  #初始化语料self.model = Nonedef initialize_model(self):"""初始化"""algorithm = self.algorithmc1 = float(self.c1)c2 = float(self.c2)max_iterations = int(self.max_iterations)self.model = sklearn_crfsuite.CRF(algorithm=algorithm, c1=c1, c2=c2,max_iterations=max_iterations, all_possible_transitions=True)def train(self):"""训练"""self.initialize_model()x, y = self.corpus.generator()x_train, y_train = x[500:], y[500:]x_test, y_test = x[:500], y[:500]self.model.fit(x_train, y_train)labels = list(self.model.classes_)labels.remove('O')y_predict = self.model.predict(x_test)metrics.flat_f1_score(y_test, y_predict, average='weighted', labels=labels)sorted_labels = sorted(labels, key=lambda name: (name[1:], name[0]))print(metrics.flat_classification_report(y_test, y_predict, labels=sorted_labels, digits=3))self.save_model()def predict(self, sentence):"""预测"""self.load_model()u_sent = self.corpus.q_to_b(sentence)word_lists = [[u'<BOS>']+[c for c in u_sent]+[u'<EOS>']]word_grams = [self.corpus.segment_by_window(word_list) for word_list in word_lists]features = self.corpus.extract_feature(word_grams)y_predict = self.model.predict(features)entity = u''for index in range(len(y_predict[0])):if y_predict[0][index] != u'O':if index > 0 and y_predict[0][index][-1] != y_predict[0][index-1][-1]:entity += u' 'entity += u_sent[index]elif entity[-1] != u' ':entity += u' 'return entitydef load_model(self):"""加载模型 """self.model = joblib.load(self.model_path)def save_model(self):"""保存模型"""joblib.dump(self.model, self.model_path)
ner = CRF_NER()
ner.train()
ner.predict(u'新华社北京十二月三十一日电(中央人民广播电台记者刘振英、新华社记者张宿堂)今天是一九九七年的最后一天。')

6. 中文命名实体提取相关推荐

  1. 第14课:动手实战中文命名实体提取

    命名实体识别(Named EntitiesRecognition,NER)是自然语言处理的一个基础任务.其目的是识别语料中人名.地名.组织机构名等命名实体,比如,2015年中国国家海洋局对124个国际 ...

  2. 【项目调研+论文阅读】基于BERT的中文命名实体识别方法[J] | day6

    <基于BERT的中文命名实体识别方法>王子牛 2019-<计算机科学> 文章目录 一.相关工作 二.具体步骤 1.Bi-LSTM 2.CRF结构 三.相关实验 1.数据集 2. ...

  3. 【nlp学习】中文命名实体识别(待补充)

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一.中文分词 二.命名实体识别 1.数据处理 2.训练 3.使用预训练的词向量 4.测试训练好的模型 5.准确度判断 ...

  4. 【文本数据挖掘】中文命名实体识别:HMM模型+BiLSTM_CRF模型(Pytorch)【调研与实验分析】

    1️⃣本篇博文是[文本数据挖掘]大作业-中文命名实体识别-调研与实验分析 2️⃣在之前的自然语言课程中也完成过一次命名实体识别的实验 [一起入门NLP]中科院自然语言处理作业三:用BiLSTM+CRF ...

  5. python中文命名实体识别工具包_中文命名实体识别工具(NER)比较

    既然中文分词.词性标注已经有了,那下一步很自然想到的是命名实体识别(NER,Named-entity recognition)工具了,不过根据我目前了解到的情况,开源的中文命名实体工具并不多,这里主要 ...

  6. 中文命名实体识别---基于多特征融合嵌入

    来源: AINLPer 微信公众号(每日更新-) 编辑: ShuYini 校稿: ShuYini 时间: 2021-11-18 昨天给大家分享的是一篇EMNLP2021关于关系提取的文章,文章中将关系 ...

  7. 【ACL2021】基于边界检测增强的中文命名实体识别

    点击下面卡片,关注我呀,每天给你送来AI技术干货! 来自:复旦DISC 作者:石霭青 引言 命名实体识别(Named Entity Recognition,NER)是自然语言处理领域的一个基础任务,是 ...

  8. 基于BERT预训练的中文命名实体识别TensorFlow实现

    BERT-BiLSMT-CRF-NER Tensorflow solution of NER task Using BiLSTM-CRF model with Google BERT Fine-tun ...

  9. 代码实现中文命名实体识别(包括多种模型:HMM,CRF,BiLSTM,BiLSTM+CRF)

    作者 | 忆臻 地址 | https://zhuanlan.zhihu.com/p/100969186 专栏 | 机器学习算法与自然语言处理 代码实现中文命名实体识别(包括多种模型:HMM,CRF,B ...

最新文章

  1. 上面一个星星下面一个r_中国第一个王朝不是夏朝?山西出土一个破陶壶,上面俩字揭开谜题...
  2. cassandra集群环境搭建——注意seeds节点,DHT p2p集群管理难道初始化都应如此吗?...
  3. TCP/UDP,SOCKET,HTTP,FTP协议简析
  4. 编程方法学16:数组
  5. python与数据处理_python数据处理:数据合并和Reshaping
  6. vnc远程无法关闭窗口_vnc远程画面不能控制,vnc远程画面控制不了是什么原因?原因详解...
  7. 手机内存占用超过一半会不会卡?
  8. 在线CSV转JSON工具
  9. 160429、nodejs--Socket.IO即时通讯
  10. [系统安全] 十一.那些年的熊猫烧香及PE病毒行为机理分析
  11. 可能是数据最全的世界各国地区下拉级联,包含国际化中英文
  12. 超链接去掉下划线代码
  13. 百度云盘MP3音乐外链、视频外链教程
  14. 在vue中如何使用umy-ui
  15. 合理的电梯(水题 杭电排位赛-6)
  16. java面向对象与面向过程的区别
  17. 抖音巨量千川投放受到口碑分影响?该怎么提高口碑分?
  18. 如何有效开展小组教学_如何有效开展小组合作学习
  19. xmind可以画流程图吗_怎样用XMind方便地制作流程图
  20. Qt [GC9-14]:HUD-定速巡航、自适应巡航、车道偏离、车距保持

热门文章

  1. Windows 2003 server 搭建拨号服务器
  2. adb 强制删除系统应用
  3. 看雪4-ReeHY-main-2017
  4. 如何掌控自己的时间和生活
  5. 洛谷P2698 [USACO12MAR]Flowerpot S
  6. C#操作Excel表
  7. 计算机十一月份成绩,CPU天梯图2018年11月最新版 十一月台式电脑CPU性能排行
  8. 前端案例:像素鸟小游戏(js+dom操作,完整代码,附案例素材)
  9. js笔记十:vscode代码提示(20211221补充)
  10. 介绍两个简单好用的软件:paint 3D,FastStone Capture