樸素貝葉斯(二)實現NBCorpus分類(附代碼和數據)

理論可參考 :樸素貝葉斯(一)

公式:(P(x)爲常數,可忽略不考慮)

平滑:

Nyk是類別爲yk的樣本個數,n是特徵的維數,Nyk,xi是類別爲yk的樣本中,第i維特徵的值是xi的樣本個數,α是平滑值。


在對NBCorpus詞分類時,帶入上面的公式可得:

某詞屬於某類別的概率 = (該類別該詞的個數  + 1/ 該類別詞的總數 + 所有類別所有不重複單詞總數) ×(該類別樣本個數 / 所有類別總樣本個數) /  (所有類別該詞個數 / 所有類別所有詞個數)

所有類別該詞個數 / 所有類別所有詞個數   就是上面公式的P(x) ,它的值與類別無關,值相同,所有把它去掉,公式變成:

(該類別該詞的個數  + 1/ 該類別詞的總數 + 所有類別所有不重複單詞總數) ×(該類別樣本個數 / 所有類別總樣本個數)

(該類別樣本個數 / 所有類別總樣本個數) 就是上面公式的P(yk),即先驗概率。沒有使用平滑。

(該類別該詞的個數  + 1/ 該類別詞的總數 + 所有類別所有不重複單詞總數) 就是上面公式的P(x|yk),就是可能性。使用了平滑,分子加的1,分母加的  所有類別所有不重複單詞總數  都是平滑值。

如果按照上面的公式,就和上面的例子一樣,對於測試的樣本里的每個屬性計算出屬於每個類別的概率,對於每個類別每個屬性的概率相乘。但是,小數越乘越小,最終可能會導致數據會丟失成0,無法比較。解決辦法是對公式加ln操作,把乘法變成加法,且不破壞單調性。

分詞簡單例子:

上面的詞量比較少,沒有進行ln操作。但是如果詞量太大,舉例最後的計算變成 ln(3/4 * (3/7)^3 * 1/14 * 1/14 ) = ln(3/4) + 3*ln(3/7) + ln(1/14) + ln(1/14) 。

數據下載地址:http://download.csdn.net/download/u010668907/10263175

。。。。無語了,想上傳全部的NBCorpus庫,csdn一直說已經存在,整體的庫後續再說吧,上面的鏈接裏的是做下面算法計算的那部分,夠用了。

下面的代碼里加了ln操作,否則計算之後每個類別都是0,無法比較

# -*- coding:utf-8 -*-
# __author__='chenliclchen'
from __future__ import division
import os
import pickle


# 統計每個類別每個單詞出現的次數
# (該類別文檔數) / (所有類別文檔數)
# (該類別該單詞個數 + 1)/(該類別單詞個數 + 所有類別無重複單詞個數)

# step1,統計每個類別每個單詞出現的次數
def count_every_sort_every_word(sort_path):
    count = {}
    for item in os.listdir(sort_path):
        file_path = os.path.join(sort_path, item)
        with open(file_path) as file:
            words = file.readlines()
        for word in words:
            word = word.replace('\r\n', '')
            if word in count.keys():
                count[word] += 1
            else:
                count[word] = 1
    return count


# 保存step1的結果
def save_every_sort_every_word(count_dict, sort_path):
    file = open(sort_path, 'wb')
    pickle.dump(count_dict, file)
    file.close()


# 計算所有類別不重複單詞總數, 總詞數包括重複
def count_all_words(count_path):
    all_words_no_repeat = set()
    all_words_count = 0
    for item in os.listdir(count_path):
        file = open(os.path.join(count_path, item), 'rb')
        one_sort = pickle.load(file)
        all_words_no_repeat.update(one_sort.keys())
        for key in one_sort.keys():
            all_words_count += one_sort[key]

    return len(all_words_no_repeat), all_words_count


# 每個類別樣本數量
def count_every_sort_docu(sort_path):
    count_docu = {}
    all_docu_num = 0
    for item in os.listdir(sort_path):
        one_sort_path = os.path.join(sort_path, item)
        count_docu[item] = len(os.listdir(one_sort_path))
        all_docu_num += count_docu[item]
    count_docu['all'] = all_docu_num
    return count_docu


# 返回某個類別所有詞的數據量
def count_one_sort(sort_path):
    all_words_count = 0
    file = open(sort_path, 'rb')
    one_sort = pickle.load(file)
    file.close()
    for key in one_sort.keys():
        all_words_count += one_sort[key]
    return all_words_count


def get_test_words(test_path):
    file = open(test_path)
    words = file.readlines()
    file.close()
    for ind, word in enumerate(words):
        words[ind] = word.replace('\r\n', '')
    return words


if __name__ == '__main__':
    base_path = './NBCorpus'
    sort_path = os.path.join(base_path, 'train')
    count_path = os.path.join(base_path, 'count')
    # 計算並保存step1的數據
    for one_sort in os.listdir(sort_path):
        one_sort_path = os.path.join(sort_path, one_sort)
        one_sort_count = count_every_sort_every_word(one_sort_path)
        sort_name = os.path.split(one_sort_path)
        one_count_path = os.path.join(count_path, sort_name[-1])
        save_every_sort_every_word(one_sort_count, one_count_path)

    sort_prob = {}
    test_path = os.path.join(base_path, 'test', '487141newsML.txt')
    test_words = get_test_words(test_path)
    all_words_num, all_words_num_repeat = count_all_words(count_path)
    every_docu = count_every_sort_docu(sort_path)
    for item in os.listdir(count_path):
        one_sort_count_path = os.path.join(count_path, item)
        one_sort_num = count_one_sort(one_sort_count_path)
        file = open(one_sort_count_path, 'rb')
        one_sort_count = pickle.load(file)
        prior = every_docu[item] / every_docu['all']
        import math
        # 加入ln操作
        all_words_prob = math.log(prior)
        for word in test_words:
            word_num = one_sort_count.get(word, 0)
            word_prob = (word_num + 1) / (one_sort_num + all_words_num)
            # all_words_prob *= word_prob
            # 加入ln操作
            all_words_prob += math.log(word_prob)
        sort_prob[item] = all_words_prob
        file.close()
    print filter(lambda x:max(sort_prob.values()) == sort_prob[x], sort_prob)[0]
最終的輸出結果就是 :AFRICA

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章