说明:本文依据《中文自然语言处理入门实战》完成。目前网上有不少转载的课程,我是从GitChat上购买。
第十四课 中文命名实体提取(NER)
命名实体识别(Named EntitiesRecognition,NER)是自然语言处理的一个基础任务。其目的是识别语料中人名、地名、组织机构名等命名实体。由于命名实体数量不断增加,通常不可能在词典中穷尽列出,且其构成方法具有各自的一些规律性,因而,通常把对这些词的识别从词汇形态处理(如汉语切分)任务中独立处理,称为命名实体识别。
这部分内容在大多数项目内被归入到了词性标注中,建议直接调用现有的库来进行词法标注。
1.命名实体识别方法
- 基于规则和词典的方法:基于规则的方法多采用语言学专家手工构造规则模板,选用特征包括统计信息、标点符号、关键字、指示词和方向词、位置词(如尾字)、中心词等方法,以模式和字符串相匹配为主要手段,这类系统大多依赖于知识库和词典的建立。
- 基于统计的方法:基于统计机器学习的方法主要包括隐马尔可夫模型(HiddenMarkovMode,HMM)、最大熵(MaxmiumEntropy,ME)、支持向量机(Support VectorMachine,SVM)、条件随机场(ConditionalRandom Fields,CRF)等。
- 混合方法:自然语言处理并不完全是一个随机过程,单独使用基于统计的方法使状态搜索空间非常庞大,必须借助规则知识提前进行过滤修剪处理。目前几乎没有单纯使用统计模型而不使用规则知识的命名实体识别系统,在很多情况下是使用混合方法。
2.命名实体识别一般流程
- 对需要进行提取的文本语料进行分词;
- 获取需要识别的领域标签,并对分词结果进行标签标注;
- 对标签标注的分词进行抽取;
- 将抽取的分词组成需要的领域的命名实体。
3.使用库实现命名实体识别
使用了两种方法,extract_tags和textrank,效果应该是 textrank 略好。
jieba
import jieba import jieba.analyse import jieba.posseg as posg sentence=u'''前段时间屁股上长了一个疖肿,就是那种大概长时间坐着不动也不透气形成的小肿块,有时候会自己消有时候会化脓比较麻烦,之前也长过,但没几天就自己消了,加上单位请假手续很繁琐,所以就没去管它。但谁知道这次的疖肿比较顽固,一个礼拜都没消,反而越长越大越长越鼓,搞的我不管走路还是坐着都很疼,所以还是去了医院。到门诊,医生端详了一会儿说,是疖肿没错,不过你这玩意有点大,打消炎针没什么太大效果,手术吧,一刀子给你把脓放了,干净利落。于是大笔一挥就给我派到门诊的手术室去了。''' # 使用 jieba 进行词性切分,allowPOS 指定允许的词性,这里选择名词 n 和地名 ns kw1=jieba.analyse.extract_tags(sentence,topK=20,withWeight=True,allowPOS=('n','ns')) for item in kw1: print("extract_tags: ",item) #extract_tags: ('疖肿', 1.6301955685772724) # extract_tags: ('门诊', 0.8040392587845454) # extract_tags: ('不透气', 0.5319751397545455) # extract_tags: ('玩意', 0.4729168222954545) # extract_tags: ('干净利落', 0.46771635178636367) # extract_tags: ('消炎', 0.4435246784354545) # extract_tags: ('手术室', 0.4362096617622727) # extract_tags: ('肿块', 0.4321012953318182) # extract_tags: ('前段时间', 0.4177794295754546) # extract_tags: ('礼拜', 0.38606844911454546) # extract_tags: ('刀子', 0.3770397993490909) # extract_tags: ('走路', 0.3426988715636364) # extract_tags: ('屁股', 0.3361995217472727) # extract_tags: ('手术', 0.3223973958309091) # extract_tags: ('医生', 0.28727172271590906) # extract_tags: ('效果', 0.27164743032227273) # extract_tags: ('医院', 0.26649142805772724) # extract_tags: ('有点', 0.2544732662318182) # extract_tags: ('单位', 0.24367022607227273) kw2=jieba.analyse.textrank(sentence,topK=20,withWeight=True,allowPOS=('n','ns')) for item in kw2: print("textrank: ",item) # textrank: ('门诊', 1.0) # textrank: ('屁股', 0.749101504091777) # textrank: ('手术', 0.749101504091777) # textrank: ('有点', 0.7462417843284372) # textrank: ('肿块', 0.5039224477102334) # textrank: ('不透气', 0.5003371274099269) # textrank: ('疖肿', 0.38111844053721106) # textrank: ('效果', 0.38111844053721106) # textrank: ('玩意', 0.37990305963779164) # textrank: ('消炎', 0.37990305963779164) # textrank: ('前段时间', 0.3757026108545894) # textrank: ('刀子', 0.3757026108545894) # textrank: ('医院', 0.3364006894642531) # textrank: ('医生', 0.3364006894642531) # textrank: ('手术室', 0.3364006894642531)
HanLP
使用PerceptronLexicalAnalyzer()对语料进行词性标注,通过匹配拿到需要的实体名词。效果比jieba要好一些
from pyhanlp import * sentence = u'''前段时间屁股上长了一个疖肿,就是那种大概长时间坐着不动也不透气形成的小肿块,有时候会自己消有时候会化脓比较麻烦,之前也长过,但没几天就自己消了,加上单位请假手续很繁琐,所以就没去管它。但谁知道这次的疖肿比较顽固,一个礼拜都没消,反而越长越大越长越鼓,搞的我不管走路还是坐着都很疼,所以还是去了医院。到门诊,医生端详了一会儿说,是疖肿没错,不过你这玩意有点大,打消炎针没什么太大效果,手术吧,一刀子给你把脓放了,干净利落。于是大笔一挥就给我派到门诊的手术室去了。''' analyzer = PerceptronLexicalAnalyzer() segs = analyzer.analyze(sentence) print(segs) arr = str(segs).split(" ") print(arr) def get_result(arr): re_list = [] ner = ['n', 'ns'] for x in arr: temp = x.split("/") if (temp[1] in ner): re_list.append(temp[0]) return set(re_list) result = get_result(arr) for r in result: print(r)