アイソモカ

知の遊牧民の開発記録

開発記録 200204 Tue (100本ノック #057, Stanford CoreNLP)

読み途中の本はあるけど(「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.

f:id:piijey:20200204221546p:plain
nlp.txt.xml_2.dot.png