這篇記錄一下自己在使用 Stanford Parser 過程中碰到的問題。

只是想要在 python 裡用一下,卻把我搞到快瘋了,果然還是要多學一點跟系統有關的知識啊…(撞牆

回到正題,這次為了投稿想要幫系統加一點學術上的東西,於是想到了用 dependency parser 來抓句子裡特定的幾個詞之間的關係,看看能不能找出什麼頭緒。當然講到 parser,第一個就想到 Stanford Parser。

要使用Stanford Parser有幾個方法:

直接使用 Stanford Parser

這大概是最直接的方法了。於是我載了一個最新的版本,去年 12 月才 release 的。載下來解壓縮之後,到目錄底下直接輸入以下指令:

./lexparser.sh data/testsent.txt

testsent.txt 是本來就包在裡面的測試檔,共有 10 行 5 個句子,都沒有斷句。

這是執行的結果:

結果主要有兩個部分,dependency tree 和 grammatical relations。而它也會自動幫你把句子斷好,所以不用擔心丟進去的是像 testsent.txt 那樣的資料。

至於要如何修改輸出格式,只要將 lexparser.sh 稍稍修改一下就可以了:

1
2
java -mx150m -cp "$scriptdir/*:" edu.stanford.nlp.parser.lexparser.LexicalizedParser \
-outputFormat "wordsAndTags,typedDependencies" edu/stanford/nlp/models/lexparser/englishPCFG.ser.gz $*

-outputFormat 之後接的那一串就是輸出格式,舉幾個例子:

  • wordsAndTags 就是一般的文字與 pos tag
  • penn 是 parsing tree
  • typedDependencies 則是字和字的 dependency

使用 Stanford Parser + NLTK

這個方法是透過 NLTK 來使用 Stanford Parser。原本以為會很順利,沒想到一直噴錯。

這是一開始的 code:

1
2
3
4
from nltk.parse.stanford import StanfordParser
dep_parser = StanfordParser('stanford-parser.jar', 'stanford-parser-3.6.0-models.jar')
sentences = dep_parser.raw_parse_sents(('this is the english parser test', 'the parser is from stanford parser'))

沒想到噴了這個錯誤:

Java command failed.
請出 Google 大神,告訴我,我的 Stanford Parser 版本太新了,要去找個舊的。

於是我乖乖地照做,載了一個 2015-04 的版本,很開心地再執行一次剛剛寫好的code。

樹長出來了🌲 但是 StanfordParser 用下去只能噴出這棵樹,我想要的是 dependency tree,所以想要用 StanfordDependencyParser 來試試看。我用了 NLTK 文件說明裡的程式碼,乖乖複製貼上抄過來。

1
2
3
4
5
6
from nltk.parse.stanford import StanfordDependencyParser
dep_parser = StanfordDependencyParser(model_path="edu/stanford/nlp/models/lexparser/englishPCFG.ser.gz")
print [parse.tree() for parse in dep_parser.raw_parse('The quick brown fox jumps over the lazy dog.')]
print [list(parse.triples()) for parse in dep_parser.raw_parse('The quick brown fox jumps over the lazy dog.')]

但事情會這麼順利嗎?當然不會,這麼順利的話我就不會寫這篇了。來瞧瞧這個錯誤:

cannot import name StanfordDependencyParser?? 當下覺得應該是版本的問題,火速又查了資工系學生和工程師的超級好朋友 Stackoverflow,果然沒錯,裡面有另個告訴我說,是因為 NLTK 版本的關係,太舊了必須升級。那就升級吧:

pip install -U nltk

這下沒問題了吧?錯錯錯你錯了,問題又出現了。

這次的錯誤訊息我終於看懂了:

NLTK was unable to find stanford-parser\.jar! Set the CLASSPATH environment variable.

就是找不到 .jar 檔嘛!那就讓他找到就好了哇。於是用了一開始的 code,裡頭有一行指定 parser 和 model 檔的,稍稍修改一下:

1
2
3
4
5
6
from nltk.parse.stanford import StanfordDependencyParser
dep_parser = StanfordDependencyParser('stanford-parser.jar', 'stanford-parser-3.6.0-models.jar')
print [parse.tree() for parse in dep_parser.raw_parse('The quick brown fox jumps over the lazy dog.')]
print [list(parse.triples()) for parse in dep_parser.raw_parse('The quick brown fox jumps over the lazy dog.')]

改完之後,雖然有點慢,不過至少東西是對的。

雖然我還沒想到怎麼處理 list 裡的東西,但至少成功讓他動起來了。感謝 Google 與 Stackoverflow 的各路大神。

使用 Extended Packages

其實這是我最早嘗試的方法,想說這樣就可以直接在 python 裡使用人家包好的東西,沒想到這個更複雜…有空嘗試之後再來補吧!先貼個 package 的連結