monolithic kernel

Ruby 1.9系でMeCabとClassifier::Bayesを使う

以下のサイトを参考にベイジアンフィルタを利用してみようと思ったのですが、Ruby 1.9.2ではそのまま動かなかったのでメモ。MeCabで日本語を分かち書きに変換し、Classifier::Bayesで推定しています。

環境は例によってUbuntuです。

MeCabのインストール

sudo aptitude install mecab mecab-ipadic-utf8 libmecab-devcd ~/src
wget http://jaist.dl.sourceforge.net/sourceforge/mecab/mecab-ruby-0.98.tar.gz
tar zxvf mecab-ruby-0.98.tar.gz cd mecab-ruby-0.98gem build mecab-ruby.gemspec
gem install mecab-ruby-0.97.gem

Classifierのインストール

sudo aptitude install libgsl0-dev
gem install classifier gsl

動作確認

以下のコードは参考にしたページのテストを少しいじったものです。

# -*- coding: utf-8 -*-
require 'classifier'
require 'stemmer'
require 'MeCab'

# 分類の設定
bayes = Classifier::Bayes.new('mac', 'windows')
wakati = MeCab::Tagger.new('-O wakati')

# 分類する便利メソッド
def train(bayes, wakati, category, text)
  parsed = wakati.parse(text)
  bayes.train(category, parsed)
  puts "original: #{text}"
  puts "MeCabed: #{parsed}"
  puts parsed.encoding.inspect
end

# 分類の学習
train(bayes, wakati, 'mac', 'iPodの設定はどのように変更したら良いですか。')
train(bayes, wakati, 'mac', 'AirPortの無線ネットワークはどうやって設定しますか。')
train(bayes, wakati, 'mac', 'MacOSXのMailはどうやって設定しますか。')
train(bayes, wakati, 'windows', 'Internet Explorer 5以降を実行しておく必要があります。')
train(bayes, wakati, 'windows', 'マイクロソフトダウンロードセンターからアップデートを取できます。')
train(bayes, wakati, 'windows', '今の仕事のためにオフィスライブベーシックを手に入れよう。')

comment = 'この書類を開くにはマイクロソフトオフィスが必要です。'
parsed = wakati.parse(comment)
puts "result original source: #{comment}"
puts "result MeCabed source: #{parsed}"

# 分類データの数値化
puts bayes.classifications(parsed).inspect

# 分類の結果
puts bayes.classify(wakati.parse(comment))

# Bayesオブジェクトの中身
p bayes

# 追加
# 一度ダンプして再度ロード
p Marshal.load(Marshal.dump(bayes))

このようにMarshalを利用してダンプすると以下のようなエラーが発生し、再度読み込むことができません。

  original: iPodの設定はどのように変更したら良いですか。
  MeCabed: iPod の 設定 は どの よう に 変更 し たら 良い です か 。
  #<Encoding:ASCII-8BIT>original: AirPortの無線ネットワークはどうやって設定しますか。MeCabed: AirPort の 無線 ネットワーク は どう やっ て 設定 し ます か 。#<Encoding:ASCII-8BIT>original: MacOSXのMailはどうやって設定しますか。MeCabed: MacOSX の Mail は どう やっ て 設定 し ます か 。#<Encoding:ASCII-8BIT>original: Internet Explorer 5以降を実行しておく必要があります。MeCabed: Internet Explorer 5 以降 を 実行 し て おく 必要 が あり ます 。#<Encoding:ASCII-8BIT>original: マイクロソフトダウンロードセンターからアップデートを取できます。MeCabed: マイクロソフト ダウンロード センター から アップデート を 取 でき ます 。#<Encoding:ASCII-8BIT>original: 今の仕事のためにオフィスライブベーシックを手に入れよう。MeCabed: 今 の 仕事 の ため に オフィスライブベーシック を 手 に 入れよ う 。#<Encoding:ASCII-8BIT>result original source: この書類を開くにはマイクロソフトオフィスが必要です。result MeCabed source: この 書類 を 開く に は マイクロソフト オフィス が 必要 です 。{"Mac"=>-60.186195920171905, "Windows"=>-53.927366061541434}Windows#<Classifier::Bayes:0x00000002bf7280 @categories={:Mac=>{:ipod=>1, :"\xE3\x81\xAE"=>3, :"\xE8\xA8\xAD\xE5\xAE\x9A"=>3, :"\xE3\x81\xAF"=>3, :"\xE3\x81\xA9\xE3\x81\xAE"=>1, :"\xE3\x82\x88\xE3\x81\x86"=>1, :"\xE3\x81\xAB"=>1, :"\xE5\xA4\x89\xE6\x9B\xB4"=>1, :"\xE3\x81\x97"=>3, :"\xE3\x81\x9F\xE3\x82\x89"=>1, :"\xE8\x89\xAF\xE3\x81\x84"=>1, :"\xE3\x81\xA7\xE3\x81\x99"=>1, :"\xE3\x81\x8B"=>3, :"\xE3\x80\x82"=>3, :airport=>1, :"\xE7\x84\xA1\xE7\xB7\x9A"=>1, :"\xE3\x83\x8D\xE3\x83\x83\xE3\x83\x88\xE3\x83\xAF\xE3\x83\xBC\xE3\x82\xAF"=>1, :"\xE3\x81\xA9\xE3\x81\x86"=>2, :"\xE3\x82\x84\xE3\x81\xA3"=>2, :"\xE3\x81\xA6"=>2, :"\xE3\x81\xBE\xE3\x81\x99"=>2, :macosx=>1, :mail=>1}, :Windows=>{:internet=>1, :explor=>1, :"\xE4\xBB\xA5\xE9\x99\x8D"=>1, :"\xE3\x82\x92"=>3, :"\xE5\xAE\x9F\xE8\xA1\x8C"=>1, :"\xE3\x81\x97"=>1, :"\xE3\x81\xA6"=>1, :"\xE3\x81\x8A\xE3\x81\x8F"=>1, :"\xE5\xBF\x85\xE8\xA6\x81"=>1, :"\xE3\x81\x8C"=>1, :"\xE3\x81\x82\xE3\x82\x8A"=>1, :"\xE3\x81\xBE\xE3\x81\x99"=>2, :"\xE3\x80\x82"=>3, :"\xE3\x83\x9E\xE3\x82\xA4\xE3\x82\xAF\xE3\x83\xAD\xE3\x82\xBD\xE3\x83\x95\xE3\x83\x88"=>1, :"\xE3\x83\x80\xE3\x82\xA6\xE3\x83\xB3\xE3\x83\xAD\xE3\x83\xBC\xE3\x83\x89"=>1, :"\xE3\x82\xBB\xE3\x83\xB3\xE3\x82\xBF\xE3\x83\xBC"=>1, :"\xE3\x81\x8B\xE3\x82\x89"=>1, :"\xE3\x82\xA2\xE3\x83\x83\xE3\x83\x97\xE3\x83\x87\xE3\x83\xBC\xE3\x83\x88"=>1, :"\xE5\x8F\x96"=>1, :"\xE3\x81\xA7\xE3\x81\x8D"=>1, :"\xE4\xBB\x8A"=>1, :"\xE3\x81\xAE"=>2, :"\xE4\xBB\x95\xE4\xBA\x8B"=>1, :"\xE3\x81\x9F\xE3\x82\x81"=>1, :"\xE3\x81\xAB"=>2, :"\xE3\x82\xAA\xE3\x83\x95\xE3\x82\xA3\xE3\x82\xB9\xE3\x83\xA9\xE3\x82\xA4\xE3\x83\x96\xE3\x83\x99\xE3\x83\xBC\xE3\x82\xB7\xE3\x83\x83\xE3\x82\xAF"=>1, :"\xE6\x89\x8B"=>1, :"\xE5\x85\xA5\xE3\x82\x8C\xE3\x82\x88"=>1, :"\xE3\x81\x86"=>1}}, @total_words=75>mecab-classifier-test.rb:44:in `load': invalid encoding symbol (EncodingError)        from mecab-classifier-test.rb:44:in `<main>'

Marshalが利用できないと学習したオブジェクトを保存しておくことができず不便なので、なんとか解決してみます。

出力を見た感じだと、どうやらMeCabとstemmerが出力した文字列のエンコーディングが正しく設定されていないことが原因のようです。このような場合にどう対処すればよいかはよく分からないのですが、今回はとりあえず自分のコードが動けばよいということで、強制的に設定するようなワークアラウンドを用意してみました。requireの直後に以下のようなコードを追加することで、今回のエラーを抑止することができます。

class String
  alias_method :original_stem, :stem

  def stem
    self.original_stem.force_encoding(self.encoding)
  end
end

class MeCab::Tagger
  alias_method :original_parse, :parse

  def parse(text)
    original_parse(text).force_encoding(text.encoding)
  end
end

この状態で実行すると出力は以下のようになり、無事ダンプすることができました。

original: iPodの設定はどのように変更したら良いですか。
MeCabed: iPod の 設定 は どの よう に 変更 し たら 良い です か 。
#<Encoding:UTF-8>original: AirPortの無線ネットワークはどうやって設定しますか。MeCabed: AirPort の 無線 ネットワーク は どう やっ て 設定 し ます か 。#<Encoding:UTF-8>original: MacOSXのMailはどうやって設定しますか。MeCabed: MacOSX の Mail は どう やっ て 設定 し ます か 。#<Encoding:UTF-8>original: Internet Explorer 5以降を実行しておく必要があります。MeCabed: Internet Explorer 5 以降 を 実行 し て おく 必要 が あり ます 。#<Encoding:UTF-8>original: マイクロソフトダウンロードセンターからアップデートを取できます。MeCabed: マイクロソフト ダウンロード センター から アップデート を 取 でき ます 。#<Encoding:UTF-8>original: 今の仕事のためにオフィスライブベーシックを手に入れよう。MeCabed: 今 の 仕事 の ため に オフィスライブベーシック を 手 に 入れよ う 。#<Encoding:UTF-8>result original source: この書類を開くにはマイクロソフトオフィスが必要です。result MeCabed source: この 書類 を 開く に は マイクロソフト オフィス が 必要 です 。{"Mac"=>-60.186195920171905, "Windows"=>-53.927366061541434}Windows#<Classifier::Bayes:0x00000001378c18 @categories={:Mac=>{:ipod=>1, :の=>3, :設定=>3, :は=>3, :どの=>1, :よう=>1, :に=>1, :変更=>1, :し=>3, :たら=>1, :良い=>1, :です=>1, :=>3, :。=>3, :airport=>1, :無線=>1, :ネットワーク=>1, :どう=>2, :やっ=>2, :て=>2, :ます=>2, :macosx=>1, :mail=>1}, :Windows=>{:internet=>1, :explor=>1, :以降=>1, :を=>3, :=>1, :し=>1, :て=>1, :おく=>1, :必要=>1, :が=>1, :あり=>1, :=>2, :。=>3, :マイクロソフト=>1, :ダウンロード=>1, :センター=>1, :から=>1, :アップデート=>1, :取=>1, :でき=>1, :今=>1, :の=>2, :仕事=>1, :ため=>1, :に=>2, :オフィスライブベーシック=>1, :手=>1, :入れよ=>1, :う=>1}}, @total_words=75>#<Classifier::Bayes:0x0000000135af38 @categories={:Mac=>{:ipod=>1, :の=>3, :設定=>3, :は=>3, :どの=>1, :よう=>1, :に=>1, :変更=>1, :し=>3, :たら=>1, :良い=>1, :です=>1, :=>3, :。=>3, :airport=>1, :無線=>1, :ネットワーク=>1, :どう=>2, :やっ=>2, :て=>2, :ます=>2, :macosx=>1, :mail=>1}, :Windows=>{:internet=>1, :explor=>1, :以降=>1, :を=>3, :=>1, :し=>1, :て=>1, :おく=>1, :必要=>1, :が=>1, :あり=>1, :=>2, :。=>3, :マイクロソフト=>1, :ダウンロード=>1, :センター=>1, :から=>1, :アップデート=>1, :取=>1, :でき=>1, :今=>1, :の=>2, :仕事=>1, :ため=>1, :に=>2, :オフィスライブベーシック=>1, :手=>1, :入れよ=>1, :う=>1}}, @total_words=75>