利用pyltp進行實體識別

一.實體識別做爲信息抽取中基礎的也是重要的一步,其技術能夠分爲三類,分別是其於規則的方法、其於統計模型的方法以及基於深度學習的方法。html

基於規則的方法,主要依靠構建大量的實體抽取規則,通常由具備必定領域知識的專家手工構建。而後將規則與文本進行匹配,識別出實體。app

基於統計的方法,須要必定的標註語料進行訓練,採用的基本模型有馬爾可夫HMM、條件馬爾可夫CMM、最大熵ME以及條件隨機場CRF等,這此方法做爲序列標註問題進行處理,主要涉及步驟有語料標註、特徵定義和模型訓練。post

基於深度的方法,也是目前比較大熱的研究方向。最經常使用的也是你們熟悉的模型有LSTM-CRF、LSTM-CNN-CRF以及基於attention注意力機制的方法等。學習

下面初步使用哈工大的pyltp進行實體識別的程序,程序開始前須要下載官方的一些模型有分詞模型cws.model」,詞性標註模型「pos.model」以及實體識別模型「ner.model「。spa

下面是pyltp官網的模型下載頁面,地址是http://ltp.ai/download.html。code


二.程序htm

  1 # -*- coding: utf-8 -*-
  2 import os
  3 from pyltp import Segmentor, Postagger, Parser, NamedEntityRecognizer
  4 from collections import OrderedDict
  5 
  6 class LtpParser():
  7     def __init__(self):
  8         LTP_DIR = "../ltp_model"
  9         self.segmentor = Segmentor()
 10         self.segmentor.load_with_lexicon(os.path.join(LTP_DIR, "cws.model"), os.path.join(LTP_DIR, "word_dict.txt")) #加載外部詞典
 11 
 12         self.postagger = Postagger()
 13         self.postagger.load_with_lexicon(os.path.join(LTP_DIR, "pos.model"), os.path.join(LTP_DIR, "n_word_dict.txt")) #加載外部詞典
 14 
 15         # self.parser = Parser()
 16         # self.parser.load(os.path.join(LTP_DIR, "parser.model")) #依存句法分析
 17 
 18         self.recognizer = NamedEntityRecognizer()
 19         self.recognizer.load(os.path.join(LTP_DIR, "ner.model"))#實體識別
 20 
 21         # #加載停詞
 22         # with open(LTP_DIR + '/stopwords.txt', 'r', encoding='utf8') as fread:
 23         #     self.stopwords = set()
 24         #     for line in fread:
 25         #         self.stopwords.add(line.strip())
 26 
 27     '''把實體和詞性給進行對應'''
 28     def wordspostags(self, name_entity_dist, words, postags):
 29         pre = ' '.join([item[0] + '/' + item[1] for item in zip(words, postags)])
 30         post = pre
 31         for et, infos in name_entity_dist.items():
 32             if infos:
 33                 for info in infos:
 34                     post = post.replace(' '.join(info['consist']), info['name'])
 35         post = [word for word in post.split(' ') if len(word.split('/')) == 2 and word.split('/')[0]]
 36         words = [tmp.split('/')[0] for tmp in post]
 37         postags = [tmp.split('/')[1] for tmp in post]
 38 
 39         return words, postags
 40 
 41     '''根據實體識別結果,整理輸出實體列表'''
 42     def entity(self, words, netags, postags):
 43         '''
 44         :param words: 詞
 45         :param netags: 實體
 46         :param postags: 詞性
 47         :return:
 48         '''
 49         name_entity_dict = {}
 50         name_entity_list = []
 51         place_entity_list = []
 52         organization_entity_list = []
 53         ntag_E_Nh = ""
 54         ntag_E_Ni = ""
 55         ntag_E_Ns = ""
 56         index = 0
 57         for item in zip(words, netags):
 58             word = item[0]
 59             ntag = item[1]
 60             if ntag[0] != "O":
 61                 if ntag[0] == "S":
 62                     if ntag[-2:] == "Nh":
 63                         name_entity_list.append(word + '_%s ' % index)
 64                     elif ntag[-2:] == "Ni":
 65                         organization_entity_list.append(word + '_%s ' % index)
 66                     else:
 67                         place_entity_list.append(word + '_%s ' % index)
 68                 elif ntag[0] == "B":
 69                     if ntag[-2:] == "Nh":
 70                         ntag_E_Nh = ntag_E_Nh + word + '_%s ' % index
 71                     elif ntag[-2:] == "Ni":
 72                         ntag_E_Ni = ntag_E_Ni + word + '_%s ' % index
 73                     else:
 74                         ntag_E_Ns = ntag_E_Ns + word + '_%s ' % index
 75                 elif ntag[0] == "I":
 76                     if ntag[-2:] == "Nh":
 77                         ntag_E_Nh = ntag_E_Nh + word + '_%s ' % index
 78                     elif ntag[-2:] == "Ni":
 79                         ntag_E_Ni = ntag_E_Ni + word + '_%s ' % index
 80                     else:
 81                         ntag_E_Ns = ntag_E_Ns + word + '_%s ' % index
 82                 else:
 83                     if ntag[-2:] == "Nh":
 84                         ntag_E_Nh = ntag_E_Nh + word + '_%s ' % index
 85                         name_entity_list.append(ntag_E_Nh)
 86                         ntag_E_Nh = ""
 87                     elif ntag[-2:] == "Ni":
 88                         ntag_E_Ni = ntag_E_Ni + word + '_%s ' % index
 89                         organization_entity_list.append(ntag_E_Ni)
 90                         ntag_E_Ni = ""
 91                     else:
 92                         ntag_E_Ns = ntag_E_Ns + word + '_%s ' % index
 93                         place_entity_list.append(ntag_E_Ns)
 94                         ntag_E_Ns = ""
 95             index += 1
 96         name_entity_dict['nhs'] = self.modify(name_entity_list, words, postags, 'nh')
 97         name_entity_dict['nis'] = self.modify(organization_entity_list, words, postags, 'ni')
 98         name_entity_dict['nss'] = self.modify(place_entity_list, words, postags, 'ns')
 99         return name_entity_dict
100 
101     def modify(self, entity_list, words, postags, tag):
102         modify = []
103         if entity_list:
104             for entity in entity_list:
105                 entity_dict = {}
106                 subs = entity.split(' ')[:-1]
107                 start_index = subs[0].split('_')[1]
108                 end_index = subs[-1].split('_')[1]
109                 entity_dict['stat_index'] = start_index
110                 entity_dict['end_index'] = end_index
111                 if start_index == entity_dict['end_index']:
112                     consist = [words[int(start_index)] + '/' + postags[int(start_index)]]
113                 else:
114                     consist = [words[index] + '/' + postags[index] for index in
115                                range(int(start_index), int(end_index) + 1)]
116                 entity_dict['consist'] = consist
117                 entity_dict['name'] = ''.join(tmp.split('_')[0] for tmp in subs) + '/' + tag
118                 modify.append(entity_dict)
119         return modify
120 
121     '''詞性和實體'''
122     def post_ner(self, words):
123         postags = list(self.postagger.postag(words))
124         # words_filter =[]
125         # postags = []
126         # for word, postag in zip(words, self.postagger.postag(words)):
127         #     if 'n' in postag:
128         #         postags.append(postag)
129         #         words_filter.append(word)
130         nerags = self.recognizer.recognize(words, postags)
131         return postags, nerags
132 
133     def parser_process(self, sentence):
134         words = list(self.segmentor.segment(sentence))
135         post, ner = self.post_ner(words)  # 詞性和實體
136         name_entity_dist = self.entity(words, ner, post)
137         words, postags = self.wordspostags(name_entity_dist, words, post)
138         return words, postags
139 
140 if __name__ == '__main__':
141     content_1 = '提起本山傳媒,相信你們應該再熟悉不過了。近日,文化產業新聞查詢資料顯示,趙本山旗下的本山傳媒有限公司,在今年的8月1號已經更名,改爲了遼寧民間藝術團有限公司,去掉了趙本山的效應。而此前不少以趙本山名字冠名的組織,也已經改名了。        此前在2015年6月9日,遼寧大學官宣將遼寧大學本山藝術學院改名爲遼寧大學藝術學院。    其實,公司更名也早有預料,這幾年本山傳媒的演員參加《歡樂喜劇人》《喜劇總動員》等綜藝節目時,一直都宣稱來自遼寧民間藝術團,楊樹林更是以團長自居。    據文化產業新聞查詢,本山傳媒是以遼寧民間藝術團爲核心組建成的大型文化產業集團,由表演藝術家趙本山任集團董事長。被文化部授予「文化企業三十強」。本山傳媒前身爲遼寧民間藝術團,成立於2003年,是遼寧省文化廳直屬的民營文化企業。    本山傳媒是集演藝、影視、藝術教育於一身的大型文化產業集團。2004年,被文化部授予首批「文化產業示範基地」;2010年,「劉老根大舞臺」被文化部、國家旅遊局聯合評爲首批「國家文化旅遊重點項目」;2010年起連續三年被中宣部評爲「全國文化企業三十強」。    本山傳媒拍攝有「劉老根」「鄉村愛情故事」「馬大帥」等享譽全國的優秀影視做品。      更名後的「本山傳媒」股東結構如何?    雖然更名了,但持股人都是趙本山和馬立娟,實打實的肥水不流外人田。    經過股份佔有樹狀圖能夠看到,股東分別是本山控股有限公司、趙本山及其妻子馬立娟。          其中,本山控股有限公司佔股60%、趙本山和馬立娟分別佔19.6%、20.4%,馬麗娟是疑似實際控制人,但最終受益人還是趙本山和馬麗娟夫妻二人,沒有第三者,能夠說是實打實的「自家產業」了。        爲什麼「去本山化」    趙本山之因此將公司更名,確定不僅是由於好聽,還有更深的意義!    一方面是爲了更進一步的「去本山化」。這幾年本山傳媒公司一直在努力的「去本山化」,爲的固然就是擺脫對趙本山我的名望的依賴。    以前,楊樹林等人在進行活動的時候,就介紹本身是遼寧民間藝術團,實質就已經在爲人氣和知名度作出了必定的鋪墊,畢竟到了必定程度,公司也是須要轉型的。    值得一提的是,其實本山傳媒的前身是遼寧民間藝術團,但在趙本山事業鼎盛時期接受了他,並用本身的名字來命名,能夠看出是爲了打造必定的知名度。儘管如今培育出的人才衆多,可是被你們熟知的卻極少,所以「去本山化」可謂是早晚的事情。    隨着本山傳媒的改名,不少網友不由感嘆,這是一個時代的結束。    這幾年本山傳媒是在走下坡路。不但趙本山本身也不上春晚了,就連徒弟們也相繼淡出你們的視野。之前上過春晚的丫蛋,小瀋陽等,如今已經淪爲十八線明星了。就連曾經和馬雲拍太小品的宋小寶近年來也消聲滅跡了。        此次本山傳媒改名,大衆認爲去本山化傾向明顯,回望本山傳媒早期,是依靠趙本山老師一我的的知名度去闖天地。可是,隨着現代文化公司運營的逐漸正規化,愈來愈多的文化公司開始注重打造公司品牌而再也不注重我的品牌效應,因此這一次公司的更名,是對現代文化公司商業運營的重大轉變。    倉促中擬寫此文,記念本山傳媒,記念本山時代。'
142     ltp = LtpParser()
144     words, postags = ltp.parser_process(content_1)
145 
146     NER_1 = OrderedDict()
147     for index, tag in enumerate(postags):
148         if tag == 'ni' and len(words[index]) > 1: #組織名
149             NER_1.setdefault('ORG', set()).add(words[index])
150         elif tag == 'nh' and len(words[index]) > 1:#人名
151             NER_1.setdefault('PER', set()).add(words[index])
152         elif tag == 'ns' and len(words[index]) > 1:#地名
153             NER_1.setdefault('LOC', set()).add(words[index])
154     print(NER_1)

 三.結果blog

OrderedDict([('LOC', {'趙本山', '遼寧省', '本山', '瀋陽'}), ('PER', {'趙本山', '馬麗娟', '本山', '馬立娟', '楊樹林', '劉老根', '宋小寶', '官宣'}), ('ORG', {'國家旅遊局', '遼寧民間藝術團有限公司', '本山傳媒有限公司', '遼寧民間藝術團', '文化部', '遼寧大學', '本山傳媒公司', '中宣部'})])
結果中把''趙本山‘,’本山‘看成LOC了。這裏能夠引入外部詞典解決。ip

相關文章
相關標籤/搜索