読者です 読者をやめる 読者になる 読者になる

不可視点

search guy at cookpad.com

MeCabの辞書にはてなキーワードを追加しよう

MeCab形態素解析のためのソフトウェアです。日本語を分かち書きするために使われるものとしては最も人気の高いものだと思われますが、チャットや掲示板に書き込まれるような崩した日本語や、正しく書かれた日本語でも新語を期待した通りに分かち書きしてくれないことがあります。これはMeCabの内部で使われている辞書が一般的な言葉を情報源としているわけではないことに関係があります。MeCabというか、より一般的な話ですが以下のような認識が一般的かと思われます。

というのも、一番広く使われているであろう自然言語処理技術は形態素解析(単語分かち書き、と言ったほうがいいのかもしれない)であろうが、これは現在99%くらいの精度になっていて、すでに人間がやるより遙かに高精度で行えるのだが、これだけ高い精度が出せるのは新聞記事を相手にしたときだけであって、それは新聞記事をコーパスとして用いる機械学習により形態素解析器を作っているので仕方ない面はあるが、医療分野や特許分野のように専門分野になったりウェブ文書を相手にしたりすると、一気に精度が落ち込むのは広く知られた事実である。大規模なコーパスがある状況で、実際に適用したい分野がそのコーパスと違う状況でも精度を落とさず解析できるようにしましょう、というのは自然言語処理の言葉では分野適応というのだが、これもここ数年研究が始まったばかりで、機械翻訳の現状を見ると「こうすれば万事解決」というようなものではない。(もっとも、ある分野を解析したいとして、数千語辞書を作れば精度95%くらいには上がるそうなので、現実的には地道に辞書を作ればいい、という話でもある)

Wolfram|alpha や Bing のすごくないがゆえにすごいところ - 生駒日記

じゃあ辞書ってどこにあんの

現在MeCabではnaist-jdicという辞書が推奨されています。5月の下旬に最新版が更新されています。

しかし、前述の通りこれだけでは最新の単語に対応することは出来ません。そこで辞書として新語やネット上で一般的な言葉でMeCabに入っていないような語はどこにあるんだと考えたところ、エリートスパム集団はてなのはてなキーワードwikipediaの項目名が浮かびました。Googleで単語検索したとき誰もが目にする情報源ですから関心を持って項目を更新している方が多いと思われ、今後もしばらく有用であると考えられます。
両方とも公式に最新のダンプが公開されています。入手方法は以下を参照してください。

単語数:24万(2009年5月)

page_namespace=0の項目数:85万(2008年12月)
かなり性質の違うものなので項目数以上のことは特に調べていません。注意点としては両方とも日付など単語として不適な項目が含まれていることです。目的に応じて中身をチェックしておくことが必要です。
今回ははてなキーワードを追加してみます。

MeCabのインストール

以下はCentOS5,MacOSXで使うためのメモです。*1(19:58追記)
依存ライブラリ等が入っていない場合は下記のコマンドの前に公式のインストールガイドを参照してインストールしてください。

MeCab

wget http://nchc.dl.sourceforge.net/sourceforge/mecab/mecab-0.98pre3.tar.gz
tar xzvf mecab-0.98pre3.tar.gz
cd mecab-0.98pre3
./configure && make
sudo make install

naist-jdic

MeCabだけではまだ利用できません。MeCabが利用する辞書をインストールしましょう。naist-jdicを使います。

wget http://iij.dl.sourceforge.jp/naist-jdic/40117/mecab-naist-jdic-0.6.0-20090616pre3.tar.gz
tar xzvf mecab-naist-jdic-0.6.0-20090616pre3.tar.gz
cd mecab-naist-jdic-0.6.0-20090616pre3
./configure --with-charset=utf8
make
sudo make install

デフォルトだと辞書が/usr/local/lib_mecab/dic/naist-jdicに作成されます。

sudo vi /usr/local/etc/mecabrc

にて利用する辞書を選択できるので作成したnaist-jdicを利用するように変更します。

dicdir = /usr/local/lib/mecab/dic/ipadic
を以下のように変更
dicdir = /usr/local/lib/mecab/dic/naist-jdic

テスト

これでMeCabが使えるようになりました。プロンプトで以下のようにして動作を確認してください。

echo ずっと日曜日ならいいのに | mecab
ずっと日曜日ならいいのに
ずっと 副詞,一般,*,*,*,*,ずっと,ズット,ズット
日曜日 名詞,副詞可能,*,*,*,*,日曜日,ニチヨウビ,ニチヨービ
なら 助動詞,*,*,*,特殊・ダ,仮定形,だ,ナラ,ナラ
いい 形容詞,自立,*,*,形容詞・イイ,基本形,いい,イイ,イイ
のに 助詞,接続助詞,*,*,*,*,のに,ノニ,ノニ
EOS

辞書の更新

MeCabはユーザーが辞書を更新することが出来ます。MeCab: 単語の追加方法を参考にはてなキーワードを追加します。
mecab-naist-jdic-0.6.0-20090616pre3/で作業します。はてなキーワードをダウンロードして辞書に追加します。

wget http://d.hatena.ne.jp/images/keyword/keywordlist_furigana.csv -O hatena.txt
nkf -Ew hatena.txt | python createDict.py | nkf -e > hatenakeyword.csv

辞書の構築では辞書候補として.csvが自動選択されるため、はてなキーワードはhatena.txtにリネームして保存していることに注意してください。
createDict.pyってなんだよ。って話なんですが、はてなキーワードcsvMeCabの辞書csvのフォーマットが異なるため、整形するためのフィルタです。
僕は文字コードが非常に苦手ですのでファイル整形にPythonを使いましたがPythonの中はUTF8でやりたかったのでまぬけなnkfが付いてます。
vi createDict.pyなどして以下のようなスクリプトを配置した上で、上記のコマンドを実行してください。

# -*- encoding: utf-8 -*-
import sys
import re

#数字四桁が入ったキーワードは役に立ちませんので検出して飛ばします。
year = re.compile("[0-9]{4}")

#驚くべきことにはてなキーワードには%00というキーワードがありますが、
#これがcsvとして提供されているダンプではヌル文字になっているのでシステム制御文字を非許可にします。
ng = [chr(i) for i in range(0,32)] 

def main():        
        for x in sys.stdin:
                if re.search(year,x):
                        continue #日付スキップ
                k = x.split("\t")[1].strip()
                if len(k) < 2:
                        continue #一文字スキップ
                for word in ng:
                        if word in k:
                                continue #システム制御文字スキップ
                k = k.lower() #MeCabはケースセンシティブなので小文字に統一して辞書作成
                cost = int(max(-36000, -400 * len(k)**1.5)) #コストについては後述
                print "%s,0,0,%s,名詞,一般,*,*,*,*,%s,*,*,はてなキーワード," % (k,cost,k) #0については後述
if __name__ == '__main__':
  main()

若干複雑になってきましたが、以下のような物が作成されていればokです。

grep "google wave" hatenakeyword.csv | nkf -Ew
google wave,0,0,-14593,名詞,一般,*,*,*,*,google wave,*,*,はてなキーワード,

ここまで確認できたら辞書を再構築してインストールし直しましょう。

make clean && make
sudo make install

辞書が再構築され、はてなキーワードMeCabでも切り出せるようになったことを確認してください。

echo ニコニコ動画車載動画は楽しいですが東のエデンの方が面白い。 | mecab
ニコニコ動画 名詞,一般,*,*,*,*,ニコニコ動画,*,*,はてなキーワード,
の 助詞,連体化,*,*,*,*,の,ノ,ノ,,
車載動画 名詞,一般,*,*,*,*,車載動画,*,*,はてなキーワード,
は 助詞,係助詞,*,*,*,*,は,ハ,ワ,,
楽しい 名詞,一般,*,*,*,*,楽しい,*,*,はてなキーワード,
です 助動詞,*,*,*,特殊・デス,基本形,です,デス,デス,,
が 助詞,接続助詞,*,*,*,*,が,ガ,ガ,,
東のエデン 名詞,一般,*,*,*,*,東のエデン,*,*,はてなキーワード,
の 助詞,連体化,*,*,*,*,の,ノ,ノ,,
方 名詞,非自立,一般,*,*,*,方,ホウ,ホー,,
が 助詞,格助詞,一般,*,*,*,が,ガ,ガ,,
面白い 形容詞,自立,*,*,形容詞・アウオ段,基本形,面白い,オモシロイ,オモシロイ,おもしろい/面白い,
。 記号,句点,*,*,*,*,。,。,。,,
EOS

単語に設定するコストと文脈IDをどう決めるか

話が前後して申し訳ないのですが、前述のcreateDict.pyの中で

                cost = int(max(-36000, -400 * len(k)**1.5)) #コストについては後述
                print "%s,0,0,%s,名詞,一般,*,*,*,*,%s,*,*,はてなキーワード," % (k,cost,k) #0については後述

としていた箇所について説明します。MeCab: 単語の追加方法によれば、

コストは,その単語がどれだけ出現しやすいかを示しています. 小さいほど, 出現しやすいという意味になります. 似たような単語と 同じスコアを割り振り, その単位で切り出せない場合は, 徐々に小さくしていけばいいと思います.

とのことなので文字列の長さに応じてコストを設定しています。gooとgoogleが同じコストで登録されるとgoogleと書いてもgooで切り出されたります。それは期待した動作ではないのでMeCab の辞書構造と汎用テキスト変換ツールとしての利用のケーススタディを参考にコストを設定しています。
これらの数値の設定によって挙動は変わるので、期待した動作にならない場合は調節してみましょう。その際にはmecabの-Nオプションを使ってどのような候補のなかで結果が選ばれたのか参照しながら進めると若干楽かもしれません。以下は上記のコスト関数で実行した例です。すべてのキーワードのコストを同じにしてはいけないことがなんとなく分かります。

#gooとgoogleについて
echo google | mecab -N2
google 名詞,一般,*,*,*,*,google,*,*,はてなキーワード,
EOS
goo 名詞,一般,*,*,*,*,goo,*,*,はてなキーワード,
gl 名詞,一般,*,*,*,*,gl,*,*,はてなキーワード,
e 記号,アルファベット,*,*,*,*,e,イー,イー,,
EOS

#もう一例
echo ニコニコ動 | mecab -N2
ニコニコ 名詞,一般,*,*,*,*,ニコニコ,*,*,はてなキーワード,
動 名詞,一般,*,*,*,*,動,ドウ,ドー,,
EOS
ニコ 名詞,一般,*,*,*,*,*
ニコ動 名詞,一般,*,*,*,*,ニコ動,*,*,はてなキーワード,
EOS

文脈ID
                print "%s,0,0,%s,名詞,一般,*,*,*,*,%s,*,*,はてなキーワード," % (k,cost,k) #0については後述

次に文脈ID(0,0,とか指定されていた部分)ですが、これは正直に言うとどのような数値を設定するのが妥当なのかわかりません。ただし、-1によって自動判定してくれる機能がバグっていて利用できないので1345とか0とか名詞,一般の他の単語にどのような数値が設定されているかを参考に設定するのがよいかもしれません。何かご存知の方は教えてくださると助かります。

*1:Xcodeを入れたMacOSX 10.5.7でも手順通りに進むことを確認しましたがnkfがデフォルトでは入っていないのでsudo port install nkfしてください。 [http://blog.livedoor.jp/dankogai/archives/51218958.html:title=404 Blog Not Found:tips - Mac OS X - には iconv も piconv も入っている]といった指摘を頂きました。加えて、wgetはデフォルトでは無かったのでcurlを利用するとよいでしょう。