トップ «前の日記(2013-03-13) 最新 次の日記(2013-03-15)» 編集

ヨタの日々

2001|08|09|10|11|12|
2002|01|02|03|04|05|06|07|08|09|10|11|12|
2003|01|02|03|04|05|06|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|
2021|01|02|03|04|05|06|07|08|09|10|11|12|
2022|01|02|03|04|05|06|07|08|09|10|11|12|
2023|01|02|03|04|05|06|07|08|12|
2024|01|02|03|04|

2013-03-14 :-(

_ 午前

0550 起床

0830 検討

_ 午後

1300 検討

1730 退勤

_

1900 機械学習

2130 飯。鮭のちゃんちゃん焼き

_ ,

ついに 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

26.1 sys -- システムパラメータと関数

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