2014/11/20

Clojure×OpenNLPに教わる英文法

 先日, 英文を読んでいたら, 文法的によくわからない一文が, むむむむ.

We remove all artificial constructs from our experiments and instead focus on running the GA the way a practitioner might.

 で, そんな時に, Google翻訳(etc)に通すのも一興ですが, 現代の機械翻訳の限界を鑑みると, 少し頼りなく感じます. そして, 構文的な繋がりだけをヒントとして表示してくれないかな, と思ってみたりします. そこで, 構文解析です.

 調べてみると, ClojureからOpenNLPが使えるようで, (OpenNLPはJavaで書かれた自然言語処理ライブラリ)少し調べてみたところ, 構文解析木を吐いてくれるモジュールclojure-opennlpがあったので, これを使って構文的な繋がりを括弧で括ってみたいと思います.

 モジュールのインストールとreplからの簡単な実行は,


に詳しいですが, 構文解析器を起動するまでの手順をピックアップすると,
  1. profile.cljの:pluginへ [clojure-opennlp "0.3.2"]を追加.
  2. OpenNLP Tool Modelsから, "en-parser-chunking.bin"をダウンロード.
  3. replを起動して, (use 'opennlp.treebank)でclojure-opennlpのパーサのライブラリをインポート.
  4. make-treebank-parserでパーサを生成.
 これで英文の構文解析ができるようになります.

 profile.cljは, ~/.leinか, Windowsなら, C:\Users\<ユーザ名>\.lein\あたりにあるleiningenの設定ファイルで, :pluginsのリストへ[clojure-opennlp "0.3.2"]を追加すると, leinの起動時に勝手にインストールしてくれます.

 replは適当な場所で起動して, こんな感じで使えます.
user> (use 'opennlp.treebank)
nil
user> (def parser (make-treebank-parser "en-parser-chunking.bin"))
#'user/parser
user> (parser ["This is a pen"])
["(TOP (S (NP (DT This)) (VP (VBZ is) (NP (DT a) (NN pen)))))"]
user> (parser ["This is a pen" "The dog is running"])
 "en-parser-chunking.bin"のところは, ダウンロードしたファイルの相対パスor絶対パスです. ダウンロードしたフォルダか保存したフォルダでreplを起動してしまうのが手っ取り早いですが.
 構文解析木は文字列として出力されるようですが, NPやSなど品詞が横に付随していています. 構文解析なので当然, 形態素解析も内包しています. 名詞だけ取り出すような作業の時にはこのような品詞付きの解析木は重宝しますが, 今回は文法的なつながりだけを見たいので, DTとかNNとかが除去された状態にしたいのでmake-treeを使います.
user> (make-tree (first (parser ["This is a pen"])))
{:tag TOP, :chunk ({:tag S, :chunk ({:tag NP, :chunk ({:tag DT, :chunk ("This")})} {:tag VP, :chunk ({:tag VBZ, :chunk ("is")} {:tag NP, :chunk ({:tag DT, :chunk ("a")} {:tag NN, :chunk ("pen")})})})})}
 Clojureの内部構造にparseされたのであとは適当なフィルターを作ればOKですね.
(use 'opennlp.treebank) ;; [clojure-opennlp "0.3.2"]

(def treebank-parser
  (make-treebank-parser "en-parser-chunking.bin"))

(defn get-chunks [tree]
  (cond
   (string? tree) tree
   (seq?    tree) (map get-chunks tree)
   (map?    tree) (get-chunks (:chunk tree))
   :else          "error"))

(defn simplify [tree]
  (cond
   (string? tree)       (symbol tree)
   (not (seq? tree))    "error"
   (empty? (rest tree)) (simplify (first tree))
   :else                (map simplify tree)))

(defn parse-en [en-text] ;; (parse-en "let me out of here !")
  (->> [en-text]
       treebank-parser first make-tree
       get-chunks
       simplify))
のようなプログラムを作成し, 括弧の関係のみが残るようにフィルタリングした結果,
user> (load-file "filter.clj")
#'user/parse-en
user> (parse-en "We remove all artificial constructs from our experiments and instead focus on running the GA the way a practitioner might .")
(We ((remove (all artificial constructs) (from (our experiments))) and (instead focus (on (running (the GA) ((the way) (a practitioner might)))))) .)
 となり, 少しは読みやすくなったかな. といった感じです.
 なお, 上記の括弧の文法的な正しさは保証できませんのであしからず.

 clojure-opennlpを弄っていて気づいたのですが, このmake-treeで生成された構文解析木を使えば, 自作の機械翻訳器ができますね. 生成されたシンタックスのパターンに沿って日本語のルールを記述していってパターンマッチすれば......

0 件のコメント :