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
[ツッコミを入れる]



