Igo : Common Lisp版
Javaで作成していた形態素解析器のCommon Lisp版も作成(cl-igo)。
バイナリ辞書はJavaで作成したものを使用するようにし、辞書の読み込み・形態素解析部分だけをcommon lispで実装した。
ユニコード文字列に対応している処理系なら、多分動くはず...。※ 確認済み処理系: sbcl-1.0.32, clisp-2.42
以下、簡単な使い方と計時。
使い方
まだプロジェクトページには何もドキュメントを書いていないので、代わりにここで使い方などを簡単に説明しておく。
;;;; sbcl-1.0.32 ;;;;;;;;;;;;;;;;; ;;;; インストール ;; 上記リンクから、cl-igo-0.1.0.tar.gzをダウンロードしておく ;; asdf-installを使ってインストール > (require :asdf-install) > (asdf-install:install "cl-igo-0.1.0.tar.gz") ;;;;;;;;;;;;;;;;; ;;;; 辞書読み込み > (require :igo) ;; 読み込み: 結構時間が掛る > (defvar *tagger* (igo:load-tagger "Javaで作成したバイナリ辞書があるディレクトリ")) ;;;;;;;;;;;;;;; ;;;; 形態素解析 ;; 形態素解析 > (igo:parse *tagger* "すもももももももものうち") ;; ((表層形 素性文字列 開始位置)) 形式のリストが返る --> (("すもも" "名詞,一般,*,*,*,*,すもも,スモモ,スモモ" 0) ("も" "助詞,係助詞,*,*,*,*,も,モ,モ" 3) ("もも" "名詞,一般,*,*,*,*,もも,モモ,モモ" 4) ("も" "助詞,係助詞,*,*,*,*,も,モ,モ" 6) ("もも" "名詞,一般,*,*,*,*,もも,モモ,モモ" 7) ("の" "助詞,連体化,*,*,*,*,の,ノ,ノ" 9) ("うち" "名詞,非自立,副詞可能,*,*,*,うち,ウチ,ウチ" 10)) ;; 分かち書き > (igo:wakati *tagger* "すもももももももものうち") --> ("すもも" "も" "もも" "も" "もも" "の" "うち")
parse関数が返す結果は、(辞書読み込み時に)若干カスタマイズが可能。
;;;; IPA辞書フォーマットに特化したカスタマイズ ;; load-tagger関数の第二引数には、素性文字列のパース(マッピング)関数が渡せる ※ デフォルトはidentity関数 > (setf *tagger* (igo:load-tagger "..." igo:*ipadic-feature-parser*)) > (igo:parse *tagger* "すもももももももものうち") --> (("すもも" (:名詞 :一般 :* :* :* :* "すもも" "スモモ" "スモモ") 0) ("も" (:助詞 :係助詞 :* :* :* :* "も" "モ" "モ") 3) ("もも" (:名詞 :一般 :* :* :* :* "もも" "モモ" "モモ") 4) ("も" (:助詞 :係助詞 :* :* :* :* "も" "モ" "モ") 6) ("もも" (:名詞 :一般 :* :* :* :* "もも" "モモ" "モモ") 7) ("の" (:助詞 :連体化 :* :* :* :* "の" "ノ" "ノ") 9) ("うち" (:名詞 :非自立 :副詞可能 :* :* :* "うち" "ウチ" "ウチ") 10)) > (funcall igo:*ipadic-feature-parser* "A,B,C,D,E,F,G,H,I") --> (:A :B :C :D :E :F "G" "H" "I") ;;;; 素性文字列の最初の一文字目以外は不要な場合 > (setf *tagger* (igo:load-tagger "..." (lambda (feature) (subseq feature 0 1)))) > (igo:parse *tagger* "すもももももももものうち") --> (("すもも" "名" 0) ("も" "助" 3) ("もも" "名" 4) ("も" "助" 6) ("もも" "名" 7) ("の" "助" 9) ("うち" "名" 10))
計時
前回と条件を合わせて計時。
計時用プログラム
(require :igo) (defvar *tagger* (igo:load-tagger "/path/to/dic-dir/")) #+SBCL (sb-ext:gc :full t) ;; 行読み込みマクロ (defmacro each-file-line ((line filepath &rest keys) &body body) `(with-open-file (#1=#:in ,filepath ,@keys) (let (,line) (loop WHILE (setf ,line (read-line #1# nil nil nil)) DO (progn ,@body))))) ;; 行読み込み時間 (time (each-file-line (line "/path/to/kokoroX256"))) ;; 解析時間 (time (each-file-line (line "/path/to/kokoroX256") (igo:wakati *tagger* line)))
結果
総処理時間(1) | 行読み込み時間(2) | 1 - 2 | |
MeCab | 28.311s | 0.216s | 28.095s |
Igo(Java) | 33.901s | 0.996s | 32.905s |
cl-igo(sbcl) | 36.084s*1 | 0.933s | 35.151s |
Java版より速くなることを期待して作っていたけど、無理だった...。
追記(2010/03/23): cl-igo-0.2.0
開発時の利便性を考慮して、APIを若干修正。
> (require :igo) > (igo:load-tagger "/path/to/dic-dir") --> #<IGO::TAGGER {EF9A509}> ;; load-tagger関数呼び出し結果は、igo:*tagger*変数に自動的に保存される > igo:*tagger* --> #<IGO::TAGGER {EF9A509}> ;; parse・wakati関数の第二引数にtaggerを渡すように変更。 ;; デフォルトでは、igo:*tagger*が使われる。 > (igo:wakati "すもももももももものうち") --> ("すもも" "も" "もも" "も" "もも" "の" "うち") ;; これは上の式と等価 > (igo:wakati "すもももももももものうち" igo:*tagger*) --> ("すもも" "も" "もも" "も" "もも" "の" "うち")
というか、ちゃんとしたドキュメントを書かなくちゃいけない...。
まだJavaのバイナリ辞書構築部分も不完全*2だし...。
でも他にもいろいろやりたいことが...。