2013-03-14 :-(
_ ,
ついに Tumblr で日記を書き始めましたね!
_ Google Reader 終了のお知らせ
Official Google Reader Blog: Powering Down Google Reader
フレッシュリーダーが終了してから Google Reader に乗り換えた[ 20101206#p04 ] んだが、お前もか。
とりあえずデータをエクスポートしておいた。
爆速Yahoo! さんが何かやってるらしいので期待 My Yahoo! - Googleリーダー、iGoogleからの乗り換えツール爆速準備中!
_ 整数 最大値
python
>>> import sys >>> -sys.maxint -2147483647
Pythonの整数型でサポートされる、最大の整数。この値は最低でも2**31-1で す。最大の負数は-maxint-1となります。正負の最大数が非対称です が、これは2の補数計算を行うためです。
ruby
irb(main):030:0> 2 ** ((1.size) * 8 -1 ) -1 => 2147483647
こうですか?
_ [ナイーブベイズ][ベイズ推定][ruby][機械学習]ナイーブベイズを用いたテキスト分類 - 人工知能に関する断創録
ruby で写経
Python の set (重複なしリスト) の代わりが分からんので uniq! するとか
d[1:] の代わりが分からんので d[1, d.length-1] みたいな。
docstring とか知りません。
# -*- encoding: utf-8 -*- # # ナイーブベイズを用いたテキスト分類 - 人工知能に関する断創録 # http://aidiary.hatenablog.com/entry/20100613/1276389337 # include Math require 'pp' def maxint() return 2 ** ((1.size) * 8 -1 ) -1 end def sum(data) return data.inject(0) {|s, i| s + i} end class NaiveBayes # Multinomial Naive Bayes def initialize() @categories = [] # カテゴリの集合 @vocabularies = [] # ボキャブラリの集合 @wordcount = {} # wordcount[cat][word] カテゴリでの単語の出現回数 @catcount = {} # catcount[cat] カテゴリの出現回数 @denominator = {} # denominator[cat] P(word|cat)の分母の値 end def train(data) # ナイーブベイズ分類器の訓練 # 文書集合からカテゴリを抽出して辞書を初期化 data.each {|d| cat = d[0] @categories << cat } @categories.each {|cat| @wordcount[cat] ||= {} @wordcount[cat].default = 0 @catcount[cat] = 0 } # 文書集合からカテゴリと単語をカウント data.each {|d| cat, doc = d[0], d[1, d.length-1] @catcount[cat] += 1 doc.each {|word| @vocabularies << word @wordcount[cat][word] += 1 } } @vocabularies.uniq! # 単語の条件付き確率の分母の値をあらかじめ一括計算しておく(高速化のため) @categories.each {|cat| sum = @wordcount[cat].values.inject(0) {|s, i| s + i} @denominator[cat] = sum + @vocabularies.length } end def classify(doc) # 事後確率の対数 log(P(cat|doc)) がもっとも大きなカテゴリを返す best = nil max = -maxint() @catcount.each_key {|cat| _p = score(doc, cat) if _p > max max = _p best = cat end } return best end def wordProb(word, cat) # 単語の条件付き確率 P(word|cat) を求める # ラプラススムージングを適用 # wordcount[cat]はdefaultdict(int)なのでカテゴリに存在しなかった単語はデフォルトの0を返す # 分母はtrain()の最後で一括計算済み return (@wordcount[cat][word] + 1).to_f / (@denominator[cat]).to_f end def score(doc, cat) # 文書が与えられたときのカテゴリの事後確率の対数 log(P(cat|doc)) を求める total = sum(@catcount.values) # 総文書数 sc = Math.log((@catcount[cat]) / total.to_f) # log P(cat) doc.each {|word| # logをとるとかけ算は足し算になる sc += Math.log(wordProb(word, cat)) # log P(word|cat) } return sc end def to_s() total = sum(@catcount.values) # 総文書数 return "documents: #{total}, vocabularies: #{@vocabularies.length}, categories: #{@categories.length}" end end if __FILE__ == $0 # Introduction to Information Retrieval 13.2の例題 data = [ ["yes", "Chinese", "Beijing", "Chinese"], ["yes", "Chinese", "Chinese", "Shanghai"], ["yes", "Chinese", "Macao"], ["no", "Tokyo", "Japan", "Chinese"] ] # ナイーブベイズ分類器を訓練 nb = NaiveBayes.new nb.train(data) p nb puts "P(Chinese|yes) = #{nb.wordProb('Chinese', 'yes')}" puts "P(Tokyo|yes) = #{nb.wordProb('Tokyo', 'yes')}" puts "P(Japan|yes) = #{nb.wordProb('Japan', 'yes')}" puts "P(Chinese|no) = #{nb.wordProb('Chinese', 'no')}" puts "P(Tokyo|no) = #{nb.wordProb('Tokyo', 'no')}" puts "P(Japan|no) = #{nb.wordProb('Japan', 'no')}" # テストデータのカテゴリを予測 test = ['Chinese', 'Chinese', 'Chinese', 'Tokyo', 'Japan'] puts "log P(yes|test) = #{nb.score(test, 'yes')}" puts "log P(no|test) = #{nb.score(test, 'no')}" puts nb.classify(test) end
出力は同じ
% ruby naivebayes.rb documents: 4, vocabularies: 6, categories: 4 P(Chinese|yes) = 0.42857142857142855 P(Tokyo|yes) = 0.07142857142857142 P(Japan|yes) = 0.07142857142857142 P(Chinese|no) = 0.2222222222222222 P(Tokyo|no) = 0.2222222222222222 P(Japan|no) = 0.2222222222222222 log P(yes|test) = -8.10769031284391 log P(no|test) = -8.906681345001262 yes
[ツッコミを入れる]