読み途中の本はあるけど(「Pythonで学ぶあたらしい統計学の教科書」と「ゼロから作る Deep Learning ❷ 自然言語処理編」)、とりあえず 100本ノックを進めよう。
言語処理100本ノック #057: 係り受け解析
57. 係り受け解析
Stanford Core NLPの係り受け解析の結果(collapsed-dependencies)を有向グラフとして可視化せよ.可視化には,係り受け木をDOT言語に変換し,Graphvizを用いるとよい.また,Pythonから有向グラフを直接的に可視化するには,pydotを使うとよい.
有向グラフ
言語処理100本ノック #044 で、係り受け木を有向グラフとして可視化した。そのときは pydot は使わずに Graphviz を使ったので、今回も Graphviz でやる。
線が "node" で、丸が "edge"。
# A -(label)-> B
dg.edge(A, B, label = label)
このように書くと、AからBに線が引けて、線の横にラベルを表示できる。
出力したグラフがわちゃわちゃしていて何かなと思ったら、1文の中に同じ語が複数回出てくる時に(たとえば "of" など)同一のエッジとして扱っていたからだった。
idx
では区別できるので、idx
と語を両方エッジに書くことで解決したが、他の方法もあるのだろうか。
解答
# knock_057.py import xml.etree.ElementTree as ET from graphviz import Digraph coding = False if coding: xmlfile = 'input.txt.xml' else: xmlfile = 'nlp.txt.xml' class Dependency: def __init__(self, typ, gid, governor, did, dependent): self.typ = typ self.i_gvn = '['+gid+']\n'+governor self.i_dpn = '['+did+']\n'+dependent self.gvn = governor self.dpn = dependent def __str__(self): return '[%s]\t%s -> %s' % (self.typ, self.gvn, self.dpn) def plot_dependencies(sentence): dg = Digraph(format='png') sid = sentence.get('id') for deps in sentence.findall('./dependencies'): if deps.get('type') != 'collapsed-dependencies': continue for dep in deps.findall('./dep'): if dep.find('governor').get('idx') == '0': continue gvn = dep.find('governor') dpn = dep.find('dependent') d = Dependency(dep.get('type'), \ gvn.get('idx'), gvn.text, \ dpn.get('idx'), dpn.text) dg.edge(d.i_gvn, d.i_dpn, label = d.typ) # gvn -(typ)-> dpn if coding: dotfilename = './data_knock_057_test/'+xmlfile+'_'+str(sid)+'.dot' dg.render(dotfilename, view=True) print(dotfilename) else: dotfilename = './data_knock_057/'+xmlfile+'_'+str(sid)+'.dot' dg.render(dotfilename, view=False) if __name__ == '__main__': tree = ET.parse(xmlfile) root = tree.getroot() for sentence in root.findall('./document/sentences/sentence'): plot_dependencies(sentence)
出力
2文目の係り受け解析結果の有向グラフ
As such, NLP is related to the area of humani-computer interaction.