洋食の日記

記事をです・ます調で書き始めれば良かったと後悔している人のブログです

SuikaというPure Rubyな形態素解析器を作成した

はじめに

Pure Ruby形態素解析Suikaを作成した。開発中でバッリバリにα版だが、思い切ってリリースすることにした。

suika | RubyGems.org | your community gem host

最も有名な形態素解析器であるMeCabもそうだが、形態素解析器は食べ物の名前がつくことが多い。「Rubyなので赤い食べ物が良いかな」と考えて、文字数とかわいらしさからSuika(スイカ)とした。

使い方

SuikaはPure Rubyで作られているため、MeCabをはじめ特別なライブラリを別途インストールする必要はない。

gem install suika

バッリバリにα版なので、機能はないに等しく、オプションなしのMeCabコマンドと同様となる。

$ irb
irb(main):001:0> require 'suika'
=> true
irb(main):002:0> tagger = Suika::Tagger.new
irb(main):003:0> puts tagger.parse('すもももももももものうち')
すもも  名詞, 一般, *, *, *, *, すもも, スモモ, スモモ
も      助詞, 係助詞, *, *, *, *, も, モ, モ
もも    名詞, 一般, *, *, *, *, もも, モモ, モモ
も      助詞, 係助詞, *, *, *, *, も, モ, モ
もも    名詞, 一般, *, *, *, *, もも, モモ, モモ
の      助詞, 連体化, *, *, *, *, の, ノ, ノ
うち    名詞, 非自立, 副詞可能, *, *, *, うち, ウチ, ウチ
=> nil

Taggerのparseメソッドは、形態素解析した結果を、StringのArrayで返す。

irb(main):004:0> tagger.parse('すもももももももものうち')
=> ["すもも\t名詞, 一般, *, *, *, *, すもも, スモモ, スモモ", "\t助詞, 係助詞, *, *, *, *, も, モ, モ", 
"もも\t名詞, 一般, *, *, *, *, もも, モモ, モモ", "\t助詞, 係助詞, *, *, *, *, も, モ, モ", 
"もも\t名詞, 一般, *, *, *, *, もも, モモ, モモ", "\t助詞, 連体化, *, *, *, *, の, ノ, ノ", 
"うち\t名詞, 非自立, 副詞可能, *, *, *, うち, ウチ, ウチ"]

実装のはなし

MeCabの作者であるTaku Kudoさんが書かれた、形態素解析器に関する本を読んで、勉強のために実装した。 ホントにわかりやすい本で、ホントすごい(語彙)。

形態素解析器の実装では、候補となる単語の検索のための、トライ木の実装が重要になるのだが、Rubyでトライ木を実装したGemがすでにあり(自作してた拙いモノはスッパリ捨てて)これを使うことにした。動作も早く、ホントすごい。

github.com

さらに、単語の品詞推定などには辞書が必要になる。これについては、Pure Pythonで書かれたJanomeという形態素解析器を参考にした (Pure Pythonで動作も軽いJanomeの存在はSuikaを開発する気合を与えてくれた)。

github.com

JanomeはIPAdicによるバイナリ辞書を同梱している。Suikaでも、IPAdicをパースしてRuby Hashにしたりしたモノを持たせることにした。Suika::Tagger.newすると、この同梱したバイナリ辞書を読み込むのだが、ここがとっても遅いので、なんとか改善したい。

おわりに

最初はRumaleの応用も兼ねて、点推定による形態素解析器(単語分割などを機械学習で行う)を遊びで作っていた。作っていると、段々とそれなりに動くものが欲しくなって、ここまで来てしまった。Ruby形態素解析する場合は、FFIMeCabを叩くNattoというGemが有名で、これをオススメする。Suikaは、まだ、遊んでみるには良いけど、使ってはいけない。

Rubyには、PythonのNLTKやSpaCyのような包括的な自然言語処理ライブラリで、コレだ!!というのはまだない。RSpecなどがそうだが、自然言語的にかけることを意識するRubyの文化と、自然言語処理は相性が良いと思っている。Ruby自然言語処理ライブラリを夢見て、Suikaの開発は、少しずつでも続けていきたいと思っている。

github.com