Pythonでベイジアンフィルターを実装してみた

久々にPythonアルゴリズムです。

Web+DB Vol56でPerlでかかれていた、ベイジアンフィルターをPythonで実装してみました。
ほぼ、本に忠実に実装しています。

恒例によって、結果の保存とかはしてません。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import MeCab
import math

class Bayesian(object):
    term_count = {}
    cat_count = {}

    def __init__(self):
        pass

    def MecabSpliter(self, text):
        m = MeCab.Tagger("-Ochasen")
        n = m.parseToNode(text.encode('utf-8'))
        words = {}
        while n.next is not None:
            if n.posid == 1 or n.posid == 2 or n.posid == 3 or n.posid == 4 or n
.posid == 5:
                words.setdefault(n.surface.lower(), 0)
                words[n.surface.lower()] += 1
            n = n.next
        return words

    def text2vec(self, text, spliter=None):
        if spliter is None:
            return self.MecabSpliter(text)
        else:
            return spliter(text)

    def train(self, wv, cat):
        for term, cnt in wv.iteritems():
            print term, cnt
            if not self.term_count.has_key(term):
                self.term_count[term] = {}
            if term in self.term_count[term]:
                self.term_count[term][cat] += cnt
            else:
                self.term_count[term][cat] = cnt 

            if term in self.cat_count:
                self.cat_count[cat] += 1
            else:
                self.cat_count[cat] = 1
    def catProb(self, cat):
        total = 0
        for k in self.cat_count:
            total += self.cat_count[k]
        return 1.0 * self.cat_count[cat] / total

    def termCnt(self, term, cat):
        if term in self.term_count:
            if cat in self.term_count[term]:
                return self.term_count[term][cat]
            else:
                return 0
        else:
            return 0

    def termProb(self, term, cat):
        return self.termCnt(term, cat) / self.cat_count[cat]

    def predict(self, vec):
        scores = {}
        for cat in self.cat_count:
            scores[cat] = self.score(vec, cat)
        return scores

    def score(self, vec, cat):
        print "tt", self.catProb(cat)
        cat_prob = math.log(self.catProb(cat) * 1.0)
        not_likely = 1.0 / (self.total_term_count() * 10)
        doc_prob = 0
        for term, count in vec.items():
            print term, count
            doc_prob += math.log(self.termProb(term, cat) or not_likely) * count
        return cat_prob + doc_prob

    def total_term_count(self):
        cnt = 0
        for k in self.cat_count:
            cnt += self.cat_count[k]
        return cnt

if __name__ == '__main__':
    filter = Bayesian()
    words = filter.text2vec(u'PerlやPythonはスクリプト言語です', filter.MecabSpl
iter)
    filter.train(words, "it")
    words = filter.text2vec(u'Perlでベイジアンフィルタを作りました。')
    filter.train(words, "it")
    words = filter.text2vec(u'pythonはニシキヘビ科の総称です。')
    filter.train(words, "science")

    words = filter.text2vec(u'Perlは楽しい')
    porb = filter.predict(words)
    print porb

    words = filter.text2vec(u'PythonとPerl')
    porb = filter.predict(words)
    print porb

    words = filter.text2vec(u'pythonはヘビ')
    porb = filter.predict(words)
    print porb

あと、雑誌に書いてあるとおりに設定されたMeCabが必要です。
apt-getで入れたものを使う場合、多少変更が必要です。

WEB+DB PRESS Vol.56

WEB+DB PRESS Vol.56