中文NLP(1) -- 開源工具 ltp 和 stanford
阿新 • • 發佈:2018-12-03
完整的程式碼和模型檔案可在我的GitHub:(程式碼是 linux 版本,windows 上執行只需要簡單調整)
https://github.com/ouprince/pyltp-stanford-nlp
windows 下執行調整如下:將父類 StanfordCoreNLP 中 buildjars 函式中的 : 改成 ; 即可
# -*- coding:utf-8 -*- import sys import os # 定義所有 StanfordNLP 的父類 class StanfordCoreNLP(object): def __init__(self,jarpath): self.root = jarpath self.tempsrcpath = "tempsrc" self.jarlist = ["ejml-0.23.jar","javax.json.jar","jollyday.jar","joda-time.jar","protobuf.jar",\ "slf4j-api.jar","slf4j-simple.jar","stanford-corenlp-3.9.2.jar","xom.jar"] self.jarpath = "" self.buildjars() def buildjars(self): for jar in self.jarlist: self.jarpath += self.root + jar + ":" # 注意如果是 windows 是 ; def savefile(self,path,sent): fp = open(path,"w") fp.write(sent) fp.close() def delfile(self,path): os.remove(path) # 詞性標註 class StanfordPOSTagger(StanfordCoreNLP): def __init__(self,jarpath,modelpath): StanfordCoreNLP.__init__(self,jarpath) self.modelpath = modelpath self.classfier = "edu.stanford.nlp.tagger.maxent.MaxentTagger" # 詞性標註主類 self.delimiter = "/" self.__buildcmd() def __buildcmd(self): self.cmdline = 'java -mx1g -cp "' + self.jarpath + '" ' + self.classfier + ' -model "' + self.modelpath + \ '" -tagSeparator ' + self.delimiter # 標註句子 def tag(self,sent): self.savefile(self.tempsrcpath,sent) tagtxt = os.popen(self.cmdline + ' -textFile ' + self.tempsrcpath,'r').read() self.delfile(self.tempsrcpath) return tagtxt # 標註檔案 def tagfile(self,inputpath,output): os.system(self.cmdline + ' -textFile ' + inputpath + ' > '+ output)
(1) pyltp 使用範例如下
# -*- coding:utf-8 -*- import sys import os from pyltp import Segmentor,Postagger,NamedEntityRecognizer # 分別匯入分詞,詞性標註,實體識別模組 from pyltp import SementicRoleLabeller # 複雜的語義角色標註模組 reload(sys) sys.setdefaultencoding("utf-8") # 載入分詞模型 model_path = "ltp3.4/cws.model" if not os.path.exists(model_path): print "model path is not exists" sys.exit() ''' 1.分詞 ''' segmentor = Segmentor() segmentor.load_with_lexicon(model_path,"ltp3.3/userdict.txt") # 載入分詞模型和使用者字典 words = segmentor.segment("在包含問題的所有解的解空間樹中") print "|".join(words) print "*"*30 ''' 2.詞性標註 ''' sent = "在 包含 問題 的 所有 解 的 解空間樹 中" words = sent.split() postagger = Postagger() postagger.load("ltp3.4/pos.model") # 匯入詞性標註模型 postags = postagger.postag(words) for word,postag in zip(words,postags): print word,postag print "*" *30 ''' 3.實體識別,人名,地名,機構名或其他專有名詞 ''' sent = "歐洲 東部 的 羅馬尼亞 , 首都 是 布加勒斯特 ,也是 一座 世界性 的 城市" words = sent.split() postags = postagger.postag(words) # 需要先詞性標註 recognizer = NamedEntityRecognizer() recognizer.load("ltp3.4/ner.model") # 實體識別模型 netags = recognizer.recognize(words,postags) for word,netag in zip(words,netags): print word,netag print "*" * 30 ''' 4.句法依存樹句法解析 ''' import nltk from nltk.tree import Tree # 匯入 nltk tree 結構 from nltk.grammar import DependencyGrammar # 匯入依存句法包 from nltk.parse import * from pyltp import Parser words = "羅馬尼亞 的 首都 是 布加勒斯特 。".split() postags = postagger.postag(words) # 先詞性標註 parser = Parser() # 將詞性標註和分詞結果都加入分析器中進行句法解析 parser.load("ltp3.4/parser.model") arcs = parser.parse(words,postags) arclen = len(arcs) conll = "" for i in xrange(arclen): # 構建Conll 標準的資料結構 if arcs[i].head == 0: arcs[i].relation = "ROOT" conll += "\t"+words[i] +"(" + postags[i] + ")" + "\t" + postags[i] + "\t" + str(arcs[i].head) + "\t" \ + arcs[i].relation + "\n" print conll print "*" * 30 ''' 5.最複雜的模組,角色標註模組,需要分詞,詞性標註,實體識別,句法解析的結果進行進一步分析 ''' sentence = "歐洲東部的羅馬尼亞,首都是布加勒斯特,也是一座世界性的城市。" # 分詞 words = " ".join(segmentor.segment(sentence)) wordlist = words.split() # 詞性標註 postags = postagger.postag(wordlist) # 句法解析 arcs = parser.parse(wordlist,postags) # 實體識別 netags = recognizer.recognize(wordlist,postags) # 接下來匯入語義角色標註模組 MODEL_DIR = "ltp3.4/pisrl.model" labeller = SementicRoleLabeller() labeller.load(MODEL_DIR) # 匯入模型 roles = labeller.label(wordlist,postags,netags,arcs) for role in roles: print "rel:",wordlist[role.index] # 謂詞 for arg in role.arguments: if arg.range.start != arg.range.end: print arg.name," ".join(wordlist[arg.range.start:arg.range.end]) else: print arg.name,wordlist[arg.range.start]
關於 ltp 的標記說明可參考:https://blog.csdn.net/hit_lingo/article/details/42639455
(2) stanford 使用範例如下
# -*- coding:utf-8 -*- import sys,os reload(sys) sys.setdefaultencoding("utf-8") curdir = os.path.dirname(os.path.abspath(__file__)) sys.path.append(curdir) from nltk import Tree ''' (1) stanford 中文詞性標註 ''' from stanford_postagger.stanford import StanfordPOSTagger root = os.path.join(curdir,"stanford_corenlp/") modelpath = os.path.join(root,"models","pos-tagger","chinese-distsim","chinese-distsim.tagger") st = StanfordPOSTagger(root,modelpath) seg_sent = "在 包含 問題 的 所有 解 的 解空間 樹 中" tag_list = st.tag(seg_sent) print tag_list ''' (2) stanford 中文實體識別 ''' from stanford_ner.stanford import StanfordNERTagger modelpath = os.path.join(root,"models","ner","chinese.misc.distsim.crf.ser.gz") st = StanfordNERTagger(root,modelpath) seg_sent = "歐洲 東部 的 羅馬尼亞 , 首都 是 布加勒斯特 , 也是 一座 世界性 的 城市" taglist = st.tag(seg_sent) print taglist ''' (3) stanford 句法解析之短語結構解析 ''' from stanford_parser.stanford import StanfordParser modelpath = os.path.join(root,"models","lexparser","chinesePCFG.ser.gz") opttype = "penn" # 賓州樹格式 或者說 短語結構樹 parser = StanfordParser(root,modelpath,opttype) result = parser.parse("羅馬尼亞 的 首都 是 布加勒斯特 。") print result # 可用 nltk 工具視覺化結果 ''' tree = Tree.fromstring(result) tree.draw() ''' ''' (4) stanford 句法解析之句法依存樹 ''' opttype = "typedDependencies" # 句法依存樹 parser = StanfordParser(root,modelpath,opttype) result = parser.parse("羅馬尼亞 的 首都 是 布加勒斯特 。") print result
關於 stanford 標記說明可參考:https://blog.csdn.net/u011847043/article/details/79595225