ベイズ分類器による極性判定

はじめに

単語への分割にはじまり,分類器での推測までできたので,ベイズ分類器として組み込みます.

実行例

ベイズ分類器で'quick money'をgoodかbadか判定するよ.

def sample_train(bayes)
  bayes.train('Nobody owns the water.','good')
  bayes.train('the quick rabbit jumps fences', 'good')
  bayes.train('buy pharmaceuticals now', 'bad')
  bayes.train('make quick money at the online casino', 'bad')
  bayes.train('the quick brown fox jumps', 'good')
end

bayes = My::Bayes.new
sample_train(bayes)

p bayes.classify('quick rabbit')
p bayes.classify('quick money')

bayes.threshold = 3.0
p bayes.classify('quick money')

10.times { sample_train(bayes) }
p bayes.classify('quick money')

結果は,

"good"	# => 'quick rabbit'
"bad"	# => 'quick money'
"unknown" # => thresholdを変えた状態での'quick money'
"bad"	# => 更に10回学習させた場合の'quick money'

ソース

require 'classifier'

module My
  class Bayes
    def initialize
      @classifier = Classifier.new
      @threshold = 1.0
    end

    attr_accessor :threshold

    # 事前学習
    def train(sentence, category)
      @classifier.train(sentence, category)
    end

    # Pr(ドキュメント|カテゴリ)を計算する
    def document_probability(document, category)
      words = WordCounter.new.count(document).result.keys
      words.inject(1) { |mul, word| mul * @classifier.probability(word, category) }
    end

    # ベイズの定理よりPr(カテゴリ|ドキュメント)を計算する
    def probability(document, category)
      document_probability(document, category) *
        (@classifier.select_category(category)).quo(@classifier.total_count)
    end

    # 最も確率の高いカテゴリを推測する
    def classify(document)
      probs = {}
      # 全カテゴリの確率を計算する
      @classifier.categories.each do |category|
        probs[category] = probability(document, category)
      end

      # しきい値 * 2番目に近いカテゴリが1番目のカテゴリより大きくないことを確認する
      prob_val = probs.values.sort.reverse
      prob_val[0] > prob_val[1] * @threshold ? probs.key(prob_val[0]) : 'unknown'
    end
  end
end

最後に

ベイズの定理による分類ができるようになった.
けど,こういうのは学習させるデータやしきい値のチューニングが大変なんだよね.