[[ノート/テキストマイニング]]~
訪問者数 &counter();      最終更新 &lastmod();~
> [[ノート/テキストマイニング/NLTK]]~
> [[ノート/テキストマイニング/Stanfordパーザー]]~
> 元ページは [[ノート/テキストマイニング/NLTK+StanfordParser]]

***サンプル 第1版 (2010/01/11) [#e0e64e6b]
大きく変更した点として、(1)モジュール(というかライブラリというか)を呼び出すようにしたこと、(2)そのために入力と出力をあまり一般性を失わないようにした(特定用途に依存した処理をはずした)こと、である。

呼び出し方は、
 #!/usr/bin/env python # encoding: utf-8
 # -*- coding: utf-8 -*-
 # coding: utf-8
 import sys
 import nltk
 from nltk import *
 import re
 from subprocess import *
 mod_path = "/usr/local/python/modules"  # 以下3行が呼び出しの設定のおまじない
 sys.path.append(mod_path)               #   このpath情報を理解させる
 
 from StanfordDependencies import stanforddependencies   # これで関数stanforddependenciesをimport
 
 f = open('colorectal_canser1.txt')      # このサンプルデータファイル中は複数の文からなる1つのabstract
 file_content = f.read()
 
 (trees, relations, wordlists) = stanforddependencies(file_content)
                                         # 3つの出力trees, relations, wordlistsがある
 ### ここからは処理結果を確認するサンプルコード
 ### まずは、それぞれの出力をプリントしてみる
 for u in trees:             # treesは各文ごとのtreeのリスト
   print u
 print "==="
 for u in relations:         # relationsは各文ごとのdependency relationのリスト
   print u
 print "==="
 for u in wordlists:         # wordlistsは各文ごとの単語リスト[('NN','aspirin'), ('VBN','work'), ...]のリスト
   print u
 print "==="
 
 ### dependencyリストを、適宜プリントしてみる。
 # 文ごとに分かれているrelations(dependencyペアのリストのリスト)を、全文通しのリスト(ペアのリスト)にする
 allrelation = []
 for u in relations:
   for v in u:
     allrelation.append(v)
 # allrelationをソートしてみる  キーはv[0], v[1], v[2]...の順
 allrelation.sort()
 
 for v in allrelation:         # 今後、allrelationリストの内容を使ってよい
   if v[0] != 'det':
     print '   ' + v[0] + ' / ' + v[1] + ' / ' + v[3] + ' *** ' + v[2] + '  ' + v[4]   
 #              v[0]は関係の名前、v[1]とv[3]は単語を標準形に直したもの、v[2]とv[4]はもとの語のまま
 ###     print '   ' + v[0] + ' / ' + v[1] + ' / ' + v[3]   # こうすればv[2]やv[4]を書かなくなる
   else:
     print '>> ' + v[0] + ' / ' + v[1] + ' / ' + v[3] + ' *** ' + v[2] + '  ' + v[4]   # detだけ除外したければここを無くしてしまえばよい

処理結果の例は
  ⇒ &ref(GetDependencies.txt);   
そのときの入力は &ref(colorectal_canser1.txt);

また、モジュールとして作ったファイル /usr/local/python/modules/StanfordDependencies.pyは
  ⇒ &ref(StanfordDependencies.py);

 # coding: utf-8
 import sys
 import nltk
 import sys
 from nltk import *
 import re
 from subprocess import *
 
 def stanforddependencies(content):
   # 入力contentは複数の文からなる文章、戻り値はStanford Dependencyの表[[関係名, 要素1, 要素2], [関係名, 要素1, 要素2], ... ] のリスト
 
   # contentを文に分割するためのNLTK内のPUNKT tokenizerを準備する
   mytokenizer = nltk.data.load('tokenizers/punkt/english.pickle')  # Need to prepare this file.
 
   # PUNKT tokenizerによって文に分割し、リストsentencesに入れる
   sentences = mytokenizer.tokenize(content)
 
   # contentに含まれる文の数を数えるカウンターを作っておく
   num_sentences = 0
 
   # Treeの最終結果を溜めるための空のリストを用意する。リストの要素はトリーである。
   trees = []
   # Dependenciesの最終結果を溜めるための空のリストを用意する。リストの要素はDependenciesリストである(リストのリスト)
   dependencies = []
 
   wordlists = []
   relations = []
 
   # あとでWordNetベースのStemmer(基本形抽出)であるWordNetLemmatizerを使うのでループ外でオブジェクト生成
   wnl = stem.WordNetLemmatizer()
 
   # あとでre (正規表現処理)を使うので、ループより外でmref, mref2を設定
   mref = re.compile(r"((\w|[-])+)\(((\w|[-])+), ((\w|[-])+)\).*", re.S) # S = DOALL
   mref2 = re.compile(r"((\S)+)-(\d{1,5})", re.S) # S = DOALL
 
   # Java Program "StanfordFromNltk.class" をNLTK内から起動するための初期化
   nltk.internals.config_java()
 
   # sentencesリストの要素ごとに以下を繰返す
   for sentence in sentences:
 
     p = nltk.internals.java(['StanfordFromNltk', '-mx512m', '-Xms512m', '-cp'], '/home/yamanouc/src/stanford:/usr/local/stanford-parser/stanford-parser.jar',
     p = nltk.internals.java(['StanfordFromNltk', '-mx512m', '-Xms512m', '-cp'],
 '/home/yamanouc/src/stanford:/usr/local/stanford-parser/stanford-parser.jar',
     stdin=PIPE, stdout=PIPE, blocking=False)
 
     q = p.communicate(input=sentence)
     s = q[0]
 
     # Stanford Parserの出力sを、トリー部分とdependency部分に分割する
     ## 空白行が2つの部分の切れ目になっているので、それを目当てに2つにsplitする。
     t = s.split('\n\n', 2)
 
     # 前半部分t[0]がトリーの印刷形になっているので、それを使う
     tree = nltk.bracket_parse(t[0])
     trees.append(tree)
 
     wordlist = []
     # トリー部分についてすべての単語のリストを作っておき、後で使う
     for u in tree.subtrees():  # subtreesメソッドはgeneratorなので要注意
       if (isinstance(u, list) and not isinstance(u[0], list)): # 自身がlistで[0]要素がlistでないノードを探す
         wordlist.append((u.node, u[0]))      # ('NN', 'aspirin')のようなノードのリストを作る
     wordlists.append(wordlist)               # 文ごとのリストwordlistを、全体のリストwordlistsにアペンドする
 
     # 後半部分t[1]がdependencyの表になっているので、それを使う
 
     relation = []
     for u in t[1].split('\n',2000):      # 改行文字でデータを行ごとに分割した上で
       m = mref.search(u)       # 正規表現で、abc_d(efg-h, ijk-l) を3つに分解
       if m:
         # m.group(3)と(5)は"xxxxx-nn"の形なので、語幹だけを抽出し語尾変化等を基本形に戻す
         w = mref2.search(m.group(3))       # 正規表現で、head語をxxxxx-nnを2つに分解
         if w:
           word = w.group(1)   # group(1)が欲しいxxxxの部分
         else:
           word = ''
         # このwordをWordNetLemmatizerを使って基本形に戻す
         for p in wordlist:
           if p[1] == word:
             if (p[0] == 'VB') or (p[0] == 'VBD') or (p[0] == 'VBN') or (p[0] == 'VBG') or (p[0] == 'VBP') or (p[0] == 'VBZ') or (p[0] == 'JJ'):
               stem3 = wnl.lemmatize(word, 'v')
             else:
               stem3 = wnl.lemmatize(word)
         w = mref2.search(m.group(5))       # 正規表現で、tail語をxxxxx-nnを2つに分解
         if w:
           word = w.group(1)   # group(1)が欲しいxxxxの部分
         else:
           word = ''
         # このwordをWordNetLemmatizerを使って基本形に戻す
         for p in wordlist:
           if p[1] == word:
             if (p[0] == 'VB') or (p[0] == 'VBD') or (p[0] == 'VBN') or (p[0] == 'VBG') or (p[0] == 'VBP') or (p[0] == 'VBZ') or (p[0] == 'JJ'):
               stem5 = wnl.lemmatize(word, 'v')
             else:
               stem5 = wnl.lemmatize(word)
 
         relation.append([m.group(1), stem3, m.group(3), stem5, m.group(5)])
         # リストrelationは、[[関係名, 要素1, 要素2], [関係名, 要素1, 要素2], ... ] のリストである
 
     relations.append(relation)
 
   # 戻り値は、(trees, relations, wordlists) である。それぞれは文ごとの出力をリストにしたもの
   return(trees, relations, wordlists)

なお、treesのノードやwordlistsで出てくるタグはUniv. PennsylvaniaのPenn TreeBankのもので、オリジナルは[[ここ(PostScriptファイル):ftp://ftp.cis.upenn.edu/pub/treebank/doc/tagguide.ps.gz]]だし、簡易表はたとえば[[ここ:http://www.comp.leeds.ac.uk/amalgam/tagsets/upenn.html]]を参照。

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS