2018年06月21日

言語処理100本ノックでPython入門 #53 - Stanford Core NLPの出力から単語抽出

  
今日は、言語処理100本ノック 2015の第6章・問題53です。

■ 問題 
53. Tokenization
Stanford Core NLPを用い,入力テキストの解析結果をXML形式で得よ.また,このXMLファイルを読み込み,入力テキストを1行1単語の形式で出力せよ.

■ Stanford Core NLPをダウンロード


以下のURLからStanford Core NLPをダウンロードします。

https://stanfordnlp.github.io/CoreNLP/


これを、corenlpというフォルダに配置します。

■ Stanford Core NLPを実行

以下のようなコマンドを投入し、Stanford Core NLPを起動します。
java -cp "/Users/xxxxxxx/corenlp/*" -Xmx3g edu.stanford.nlp.pipeline.StanfordCoreNLP -annotators tokenize,ssplit,pos,lemma,ner -file nlp.txt

これで、nlp.txt.xmlファイルが作成されます。

ちなみに、Javaのバージョンは、java version "1.8.0_101" です。

でも、作成したnlp.txt.xml見ると文の判断が正しくないので、入力ファイルを手で修正。
入力ファイルは、基本1行1文なのだけれど、Stanford Core NLPは、ピリオドが行の単位と認識するようなので、タイトル行の最後にもピリオドを付加しています。4か所くらいあったかな。

得られたXMLファイルの先頭部分を載せておきます。
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="CoreNLP-to-HTML.xsl" type="text/xsl"?>
<root>
  <document>
    <docId>nlp.txt</docId>
    <sentences>
      <sentence id="1">
        <tokens>
          <token id="1">
            <word>Natural</word>
            <lemma>natural</lemma>
            <CharacterOffsetBegin>0</CharacterOffsetBegin>
            <CharacterOffsetEnd>7</CharacterOffsetEnd>
            <POS>JJ</POS>
            <NER>O</NER>
            <Speaker>PER0</Speaker>
          </token>
          <token id="2">
            <word>language</word>
            <lemma>language</lemma>
            <CharacterOffsetBegin>8</CharacterOffsetBegin>
            <CharacterOffsetEnd>16</CharacterOffsetEnd>
            <POS>NN</POS>
            <NER>O</NER>
            <Speaker>PER0</Speaker>
          </token>
          <token id="3">
            <word>processing</word>
            <lemma>processing</lemma>
            <CharacterOffsetBegin>17</CharacterOffsetBegin>
            <CharacterOffsetEnd>27</CharacterOffsetEnd>
            <POS>NN</POS>
            <NER>O</NER>
            <Speaker>PER0</Speaker>
          </token>

■ XMLファイルを操作する

XMLファイルを読み込むには、xml.etreeライブラリを使います。
from xml.etree import ElementTree
次に、入力ファイルを指定し、nlp.txt.xmlをパースします。
xdoc = ElementTree.parse('nlp.txt.xml')
これで、読み込んだ結果がtree構造として返されます。

続いて、ルートを取得します。
root = xdoc.getroot()
このrootを使い、必要な要素を取り出していきます。
sentences = root.find('document/sentences')
で、rootの直下から、パスを指定してXML elementを取得。

さらに、
for e in sentences.findall('sentence/tokens/token/word'):
        yield e
で、word要素をすべて取り出します。 実際のテキストは、
e.text
で取得できます。


■ Pythonのコード

作成したPythonのコードです。
from xml.etree import ElementTree

def getWords():
    xdoc = ElementTree.parse('nlp.txt.xml')
    root = xdoc.getroot()
    sentences = root.find('document/sentences')
    for e in sentences.findall('sentence/tokens/token/word'):
        yield e


def main():
    with open('result53.txt', 'w', encoding='utf8') as w:
        for word in getWords():
            w.write(f'{word.text}\n')
       
if __name__ == '__main__':
    main()


ソースはGitHubでも公開しています。

■ 結果

結果の先頭部分を載せます。
ピリオドやカンマも抽出しています。本来は、これらは除外すべきかもしれませんが良しとします。
Natural
language
processing
.
From
Wikipedia
,
the
free
encyclopedia
.
Natural
language
processing
-LRB-
NLP
-RRB-
is
a
field
of
computer
science
,
artificial
intelligence
,
and
linguistics
concerned