ノート/テキストマイニング
訪問者数 1284      最終更新 2009-12-11 (金) 17:05:47

Stanford Parserのメソッドを試す

メソッドの一覧は、すぐに見られるように ここ にコピーしてある。

サンプルに載っているメソッドを使ってみる。

#!/usr/bin/env python
# encoding: utf-8
# -*- coding: utf-8 -*-
# coding: utf-8
##
import sys
import codecs
import os
sys.path.append('/usr/local/stanford-parser/stanford-parser.jar')
from java.util import *
from edu.stanford.nlp.trees import *
from edu.stanford.nlp.parser.lexparser import LexicalizedParser

### A magic for printing UTF-8 characters
sys.stdout = codecs.getwriter('utf_8')(sys.stdout)
# ここまでがおまじない

# LexicalizedParserを作る
lp = LexicalizedParser("/usr/local/stanford-parser/englishPCFG.ser.gz")
optionstring = ["-maxLength",  "65536", "-retainTmpSubcategories"]
lp.setOptionFlags(optionstring)

# 入力データを準備 (ここでは定数文字列にしてしまった) 
sent = "Lung cancer has become increasingly common in women, and gender differences in the physiology and
pathogenesis of the disease have suggested a role for estrogens."

# 上で作ったParserで、sent文字列を処理
parse = lp.apply(sent)

# まずはpennPrint()メソッドで出力 PennTreebankと同じ形式で表示される
parse.pennPrint()
print "-" * 80

# 次に、処理結果のうち文法の構造の部分からDependencyを出力
tlp = PennTreebankLanguagePack();
gsf = tlp.grammaticalStructureFactory();
gs = gsf.newGrammaticalStructure(parse);
tdl = gs.typedDependenciesCollapsed();
print(tdl);
print "-" * 80

# 最後に、処理結果をTreePrintで印刷してみる。
tp = TreePrint("penn,typedDependenciesCollapsed");
tp.printTree(parse);

このぐらいのことが、サンプルに載っている。

トリー内のノードをチェックするために、labeldYieldメソッドを試してみる。

上記の「ここまでおまじない」と書いたところまでは、そのまま生かすことにする。
その下で、次のような処理をする。

# 文字列入力titleを定数として定義
title = "Inhibition of peroxynitrite-mediated DNA strand cleavage and hydroxyl radical formation by aspirin
at pharmacologically relevant concentrations: Implications for cancer intervention."

lp = LexicalizedParser("/usr/local/stanford-parser/englishPCFG.ser.gz")
optionstring = ["-maxLength",  "65536", "-retainTmpSubcategories"]
lp.setOptionFlags(optionstring)

# 文字列titleをパーズ処理。parseメソッドについてはClass LexicalizedParserの項を参照。 
parse = lp.apply(title)

# タグ付けで「NN」(名詞)とつけられたものだけを拾ってみる
titlenouns = []           # 結果を格納するリストを準備

# 処理結果parseに対して、labeledYieldメソッドを適用。ラベル付きノードだけをリストとして取出す。
#   labeledYieldについては、Class Treeを参照。
y = parse.labeledYield()
# そのラベル付きノード(Class LabeledWord参照)は、<tag>と<word>の2つの要素がある。
# tag要素がNNのものだけを取出したいので、ループで、u.tag(をtoString()で文字列に書き直したもの)が"NN"に等しいuだけ、
#   そのuのword部分を印刷し且つリストtitlenounsにappendする。
for u in y:
  if u.tag().toString() == "NN":
     print u.word()
     titlenouns.append(u.word())
# 最後にリストtitlenousを印刷する
print titlenouns

実行した結果は、次のようになった

$ jython ExtractNouns.py
Loading parser from serialized file /usr/local/stanford-parser/englishPCFG.ser.gz ... done [2.9 sec].
Inhibition
DNA
formation
aspirin
cancer
intervention
['Inhibition', 'DNA', 'formation', 'aspirin', 'cancer', 'intervention']

この結果の妥当性を見るために、全体のトリーを書き出してみると、

(ROOT
  (S
    (NP
      (NP (NN Inhibition))
      (PP (IN of)
        (NP (JJ peroxynitrite-mediated) (NN DNA))))
    (VP (VBD strand)
      (NP
        (ADJP (JJ cleavage)
          (CC and)
          (JJ hydroxyl))
        (JJ radical) (NN formation))
      (PP (IN by)
        (NP (NN aspirin)))
      (PP (IN at)
        (NP
          (NP
            (ADJP (RB pharmacologically) (JJ relevant))
            (NNS concentrations))
          (: :)
          (NP
            (NP (NNP Implications))
            (PP (IN for)
              (NP (NN cancer) (NN intervention)))))))
    (. .)))

nsubj(strand-5, Inhibition-1)
amod(DNA-4, peroxynitrite-mediated-3)
prep_of(Inhibition-1, DNA-4)
amod(formation-10, cleavage-6)
conj_and(cleavage-6, hydroxyl-8)
amod(formation-10, radical-9)
dobj(strand-5, formation-10)
prep_by(strand-5, aspirin-12)
advmod(relevant-15, pharmacologically-14)
amod(concentrations-16, relevant-15)
prep_at(strand-5, concentrations-16)
dep(concentrations-16, Implications-18)
nn(intervention-21, cancer-20)
prep_for(Implications-18, intervention-21)

NNをもつ語だけがリストされている。

typedDependenciesCollapsed()を使って、dependencyリスト部分を抽出する

parse = lp.apply(title)
gs = PennTreebankLanguagePack().grammaticalStructureFactory().newGrammaticalStructure(parse)
x = gs.typedDependenciesCollapsed()
print x

typedDependencies(Collapsed)はgrammaticalStructureオブジェクトのメソッドなので、そのオブジェクトgsをnewGrammaticalStructureメソッドで作った上で、それに対してtypedDependenciesCollapsedメソッドを実行している。(本当にこの手続きが必要なのか?)

この結果の出力は

[nsubj(strand-5, Inhibition-1), amod(DNA-4, peroxynitrite-mediated-3), 
prep_of(Inhibition-1, DNA-4), amod(formation-10, cleavage-6),
conj_and(cleavage-6, hydroxyl-8), amod(formation-10, radical-9),
dobj(strand-5, formation-10), prep_by(strand-5, aspirin-12),
advmod(relevant-15, pharmacologically-14), amod(concentrations-16,
relevant-15), prep_at(strand-5, concentrations-16), dep(concentrations-16,
Implications-18), nn(intervention-21, cancer-20), prep_for(Implications-18,
intervention-21)]

のようになるので、リストのそれぞれの要素を取出して文字列に変換するためには、

parse = lp.apply(title)
gs = PennTreebankLanguagePack().grammaticalStructureFactory().newGrammaticalStructure(parse)
x = gs.typedDependenciesCollapsed()

# Print each element
for u in x:
  print u.reln().toString()
  print u.gov().toString()
  print u.dep().toString()
  print "---"

のようにすればよい。詳細はClass Typed Dependencyの項を参照。 その結果は

nsubj           u.reln()〜relation部分の抽出の結果
strand-5        u.gov()〜governer部分の抽出の結果
Inhibition-1    u.dep()〜dependent?部分の抽出の結果
---
amod
DNA-4
peroxynitrite-mediated-3
---
prep_of
Inhibition-1
DNA-4
---
amod
formation-10
cleavage-6
---
conj_and
cleavage-6
hydroxyl-8
以下略

のようになる。

トリーの中をうろうろしたい 〜 たとえばgetChild()やparent()で動き回る

これらのメソッドは、Class Treeに定義されている。マニュアルのClass Treeを参照。

トリーを下がるためにはgetChild(i) (但しiには左から何番目の子供かを入れる)が使える。子ノードが無いと(たとえば1つしか子が無いのに2番目(i=1)を選ぶ)エラーになる。

又トリーを上るためにはparent()がある。トリー内にアップリンクが書いて無いため、直接登ることはできず、トリー全体から探すタイプのparent(トリー全体)しか使えない。これはトリー全体を探すため、非常に遅くなると思うので、なるべくなら使わずに済ませたほうがいい。

ノードを印刷出力するため、toString()メソッドで文字列化している。

parse = lp.apply(title)      # さっき作ったトリーparse

# TREE WALK AROUND

# go down the tree "parse" along the leftmost edge.
# "getChild(0) means the leftmost child."
print "Top Node:           " + parse.toString()
print "0:                  "  + parse.getChild(0).toString()
print "0->0:               " + parse.getChild(0).getChild(0).toString()  # まずは左下へどんどん降りる
print "0->0->0:            " + parse.getChild(0).getChild(0).getChild(0).toString()
print "0->0->0->0:         " + parse.getChild(0).getChild(0).getChild(0).getChild(0).toString()
print "0->0->0->0->0:      " + parse.getChild(0).getChild(0).getChild(0).getChild(0).getChild(0).toString() # これは葉なのでこの先はエラーになる
print "------"

# Try getChild(1) to get the second leftmost child.
print "0->1:               "  + parse.getChild(0).getChild(1).toString()  # 2番目の子
print "0->1->0:            "  + parse.getChild(0).getChild(1).getChild(0).toString()
print "0->1->0->0:         "  + parse.getChild(0).getChild(1).getChild(0).getChild(0).toString()
print "------"
print "0->1->1:            "  + parse.getChild(0).getChild(1).getChild(1).toString()
print "0->1->1->0:         "  + parse.getChild(0).getChild(1).getChild(1).getChild(0).toString()
print "0->1->1->0->0:      "  + parse.getChild(0).getChild(1).getChild(1).getChild(0).getChild(0).toString()
print "0->1->1->0->0->0:   "  + parse.getChild(0).getChild(1).getChild(1).getChild(0).getChild(0).getChild(0).toString()
print "------"
print "0->1->1->1:         "  + parse.getChild(0).getChild(1).getChild(1).getChild(1).toString() # 2番目・2番目と降りた場合
print "------"
print "0->1->2:            "  + parse.getChild(0).getChild(1).getChild(2).toString()  # このレベルには3番目の子がある
print "------"
print "0->2:               "  + parse.getChild(0).getChild(2).toString()
print "------"
# use parent() to go up the tree.  Because the tree does not have upgoing link, parent() returns null.
#   To go around this problem, use parent(whole tree), but may need more search time.
print "Go Up by parent()"
print "0->0->0:            " + parse.getChild(0).getChild(0).getChild(0).toString()  # まず確認
print "0->0->0->up:        " + parse.getChild(0).getChild(0).getChild(0).parent(parse).toString()  # parentを使って0->0へ上る
print "0->0:               " + parse.getChild(0).getChild(0).toString() # 同じものか確認

実行結果

Loading parser from serialized file /usr/local/stanford-parser/englishPCFG.ser.gz ... done [2.9 sec].
Top Node:           (ROOT [214.118] (S [214.011] (NP [37.113] (NP [12.861] (NN [10.255] Inhibition))
(PP [23.886] (IN [0.666] of) (NP [22.818] (JJ [11.215] peroxynitrite-mediated) (NN [8.029] DNA))))
(VP [174.070] (VBD [11.444] strand) (NP [52.537] (ADJP [28.861] (JJ [14.597] cleavage)
(CC [0.134] and) (JJ [11.317] hydroxyl)) (JJ [8.836] radical) (NN [9.070] formation))
(PP [17.259] (IN [2.277] by) (NP [14.309] (NN [11.979] aspirin))) (PP [84.742] (IN [2.655] at)
(NP [80.431] (NP [32.168] (ADJP [20.021] (RB [10.334] pharmacologically) (JJ [7.780] relevant))
(NNS [8.459] concentrations)) (: [1.075] :) (NP [39.185] (NP [15.114] (NNP [12.053] Implications))
(PP [23.410] (IN [2.460] for) (NP [20.548] (NN [7.380] cancer) (NN [9.009] intervention))))))) (. [0.002] .)))
0:                  (S [214.011] (NP [37.113] (NP [12.861] (NN [10.255] Inhibition))
(PP [23.886] (IN [0.666] of) (NP [22.818] (JJ [11.215] peroxynitrite-mediated) (NN [8.029] DNA))))
(VP [174.070] (VBD [11.444] strand) (NP [52.537] (ADJP [28.861] (JJ [14.597] cleavage)
(CC [0.134] and) (JJ [11.317] hydroxyl)) (JJ [8.836] radical) (NN [9.070] formation))
(PP [17.259] (IN [2.277] by) (NP [14.309] (NN [11.979] aspirin))) (PP [84.742] (IN [2.655] at)
(NP [80.431] (NP [32.168] (ADJP [20.021] (RB [10.334] pharmacologically) (JJ [7.780] relevant))
(NNS [8.459] concentrations)) (: [1.075] :) (NP [39.185] (NP [15.114] (NNP [12.053] Implications))
(PP [23.410] (IN [2.460] for) (NP [20.548] (NN [7.380] cancer) (NN [9.009] intervention))))))) (. [0.002] .))
0->0:               (NP [37.113] (NP [12.861] (NN [10.255] Inhibition)) (PP [23.886] (IN [0.666] of)
(NP [22.818] (JJ [11.215] peroxynitrite-mediated) (NN [8.029] DNA))))
0->0->0:            (NP [12.861] (NN [10.255] Inhibition))
0->0->0->0:         (NN [10.255] Inhibition)
0->0->0->0->0:      Inhibition
------
0->1:               (VP [174.070] (VBD [11.444] strand) (NP [52.537] (ADJP [28.861] 
(JJ [14.597] cleavage) (CC [0.134] and) (JJ [11.317] hydroxyl)) (JJ [8.836] radical) 
(NN [9.070] formation)) (PP [17.259] (IN [2.277] by) (NP [14.309] (NN [11.979] aspirin)))
(PP [84.742] (IN [2.655] at) (NP [80.431] (NP [32.168] (ADJP [20.021] (RB [10.334] pharmacologically)
(JJ [7.780] relevant)) (NNS [8.459] concentrations)) (: [1.075] :) (NP [39.185]
(NP [15.114] (NNP [12.053] Implications)) (PP [23.410] (IN [2.460] for) (NP [20.548]
(NN [7.380] cancer) (NN [9.009] intervention)))))))
0->1->0:            (VBD [11.444] strand)
0->1->0->0:         strand
------
0->1->1:            (NP [52.537] (ADJP [28.861] (JJ [14.597] cleavage) (CC [0.134] and)
(JJ [11.317] hydroxyl)) (JJ [8.836] radical) (NN [9.070] formation))
0->1->1->0:         (ADJP [28.861] (JJ [14.597] cleavage) (CC [0.134] and) (JJ [11.317] hydroxyl))
0->1->1->0->0:      (JJ [14.597] cleavage)
0->1->1->0->0->0:   cleavage
------
0->1->1->1:         (JJ [8.836] radical)
------
0->1->2:            (PP [17.259] (IN [2.277] by) (NP [14.309] (NN [11.979] aspirin)))
------
0->2:               (. [0.002] .)
------
Go Up by parent()
0->0->0:            (NP [12.861] (NN [10.255] Inhibition))
0->0->0->up:        (NP [37.113] (NP [12.861] (NN [10.255] Inhibition)) (PP [23.886]
(IN [0.666] of) (NP [22.818] (JJ [11.215] peroxynitrite-mediated) (NN [8.029] DNA))))
0->0:               (NP [37.113] (NP [12.861] (NN [10.255] Inhibition)) (PP [23.886]
(IN [0.666] of) (NP [22.818] (JJ [11.215] peroxynitrite-mediated) (NN [8.029] DNA))))

その他、Class Treeにはいろいろなメソッドが用意されている。

isLeaf()は葉であるかをチェックする。もし葉なら1、そうでなければ0。

isPreTerminal(), isPrePreTerminal()は、ターミナルの1つ手前か、2つ手前か。

isPhrasal()は、ノードがフレーザルか否か。フレーザルとは、ノードが葉でもプレターミナルでもないもの。

firstChild, lastchildは、最初の子供、最後の子供を返す。

children(), getChildrenAsList()は、現在のノードの子を返す。


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2009-12-11 (金) 17:05:47 (2901d)