朴素Bayse新闻分类实践
目錄
- 1、信息增益(互信息)介紹
- (1)西瓜書中的信息增益[^1]
- (2)PRML中的互信息[^2]
- (3) 其實他們是一個東西
- 2、樸素Bayse新聞分類[^3]
- (1)常量及輔助函數
- (2)特征提取
- (3)訓練模型
- (4)預測
- (5)測試
- (6)測試結果
1、信息增益(互信息)介紹
由于在最終的bayse算法中只使用了部分的特征,而特征的選擇使用到了信息增益,所以在這里做一個簡單的介紹。
(1)西瓜書中的信息增益1
在西瓜書的4.2節中,選擇樹節點的劃分屬性時提到了信息增益;其定義如下:
首先是元集合D的類別信息熵
Ent(D)=?∑k=1∣y∣pklog2(pk)Ent(D)=-\sum_{k=1}^{\left | y \right |}p_{k}log_{2}(p_{k}) Ent(D)=?k=1∑∣y∣?pk?log2?(pk?)
然后根據屬性a劃分為了V個集合后,給出了信息增益的定義:
Gain(D,a)=Ent(D)?∑v=1V∣Dv∣∣D∣Ent(Dv)Gain(D, a)=Ent(D) - \sum_{v=1}^{V}\frac{\left | D^{v} \right |}{\left | D \right |}Ent(D^v) Gain(D,a)=Ent(D)?v=1∑V?∣D∣∣Dv∣?Ent(Dv)
然后利用信息增益來進行樹的劃分特征的選取。
(2)PRML中的互信息2
在PRML1.6.1中定義了互信息,公式如下:
I[x,y]≡KL(p(x,y)∣∣p(x)p(y))=??p(x,y)ln(p(x)p(y)p(x,y))dxdyI[x, y] \equiv KL(p(x, y)|| p(x)p(y)) = - \iint p(x,y)ln(\frac{p(x)p(y)}{p(x,y)}) dxdy I[x,y]≡KL(p(x,y)∣∣p(x)p(y))=??p(x,y)ln(p(x,y)p(x)p(y)?)dxdy
化簡后可以得到:
I[x,y]≡H[x]?H[x∣y]=H[y]?H[y∣x]I[x,y]\equiv H[x] - H[x|y] = H[y] - H[y|x] I[x,y]≡H[x]?H[x∣y]=H[y]?H[y∣x]
(3) 其實他們是一個東西
證明:首先把1、->(2)中的積分形式改寫成和的形式,并把ln還成log(相差了log2倍),有
?∑x,yp(x,y)log2(p(x)p(y)p(x,y))-\sum_{x,y}p(x,y)log_{2}(\frac{p(x)p(y)}{p(x,y)})?x,y∑?p(x,y)log2?(p(x,y)p(x)p(y)?)
=?∑y∑xp(x,y)log2(p(y))?(?∑xp(x)∑yp(y∣x)log2(p(y∣x)))= -\sum_{y}\sum_{x}p(x,y)log_{2}(p(y)) - (-\sum_{x}p(x)\sum_{y}p(y|x)log_{2}(p(y|x)))=?y∑?x∑?p(x,y)log2?(p(y))?(?x∑?p(x)y∑?p(y∣x)log2?(p(y∣x)))
=?∑yp(y)log2(p(y))?(?∑xp(x)∑yp(y∣x)log2(p(y∣x)))=-\sum_{y}p(y)log_{2}(p(y))-(-\sum_{x}p(x)\sum_{y}p(y|x)log_{2}(p(y|x)))=?y∑?p(y)log2?(p(y))?(?x∑?p(x)y∑?p(y∣x)log2?(p(y∣x)))
仔細觀察·是不是和1、->(1)一模一樣!如下圖所示:
2、樸素Bayse新聞分類3
(1)常量及輔助函數
import math import random import collections label_dict = {0: '財經', 1: '健康', 2: '教育', 3: '軍事', 4: '科技',5: '旅游', 6: '母嬰', 7: '汽車', 8: '體育',9: '文化', 10: '娛樂'}def code_2_label(code):return label_dict.get(code)def default_doc_dict():"""構造和類別數等長的0向量:return: 一個長度和文檔類別數相同的全0數組,用來作為某些以該長度數組為值的字典的默認返回值"""return [0] * len(label_dict)def shuffle(in_file):"""簡單的亂序操作,用于生成訓練集和測試集:param in_file: 輸入文件:return:"""text_lines = [line.strip() for line in open(in_file, encoding='utf-8')]print('正在準備訓練數據和測試數據,請稍后...')random.shuffle(text_lines)total_lines = len(text_lines)train_text = text_lines[:int(3 * total_lines / 5)]test_text = text_lines[int(3 * total_lines / 5):]print('準備訓練數據和測試數據完畢,下一步...')return train_text, test_text(2)特征提取
根據1中的信息增益(互信息)的大小來提取前100個最重要的特征(這里就是詞了)
首先定義了如下的計算互信息的輔助函數,它所計算的內容其實是:
(注意紅色的-,我把它移到了和的內部)
看起來并不是很清晰,因為是化簡以后的。這里進行一下推導:
?p(x=i,y=j)log2(p(x=i)p(y=j)p(x=i,y=j))-p(x=i,y=j)log_{2}(\frac{p(x=i)p(y=j)}{p(x=i,y=j)})?p(x=i,y=j)log2?(p(x=i,y=j)p(x=i)p(y=j)?)
=?Ni,jN?log2(NiNNjNNi,jN)=-\frac{N_{i,j}}{N}*log_{2}(\frac{\frac{N_{i}}{N}\frac{N_{j}}{N}}{\frac{N_{i,j}}{N}})=?NNi,j???log2?(NNi,j??NNi??NNj???)
=Ni,jN?log2(NNi,jNiNj)=\frac{N_{i,j}}{N}*log_{2}(\frac{NN_{i,j}}{N_{i}N_{j}})=NNi,j???log2?(Ni?Nj?NNi,j??)
=Ni,jN?ln(NNi,jNiNj)/ln(2)=\frac{N_{i,j}}{N}*ln(\frac{NN_{i,j}}{N_{i}N_{j}})/ln(2)=NNi,j???ln(Ni?Nj?NNi,j??)/ln(2)
加上平滑以后,就得到了上面的函數(別在乎1.0,只是整數轉浮點數)
=Ni,jN?ln(N(Ni,j+1)NiNj)/ln(2)=\frac{N_{i,j}}{N}*ln(\frac{N(N_{i,j}+1)}{N_{i}N_{j}})/ln(2)=NNi,j???ln(Ni?Nj?N(Ni,j?+1)?)/ln(2)
(3)訓練模型
def train_bayes(feature_file, text, model_file):"""訓練貝葉斯模型,實際上計算每個類別中特征詞的出現次數:param feature_file: 特征文件:param text: 原始的樣本:param model_file: 模型文件:return:"""print('使用樸素貝葉斯訓練中...')doc_words_count, features = load_feature_words(feature_file)feature_word_count = collections.defaultdict(default_doc_dict)# 每類文檔中特征詞出現的總次數feature_doc_words_count = [0] * len(doc_words_count)for line in text:label, text = line.strip().rstrip('\n').split(' ', 1)int_label = int(label)words = text.split(' ')for word in words:if word in features:feature_doc_words_count[int_label] += 1feature_word_count[word][int_label] += 1out_model = open(model_file, 'w', encoding='utf-8')print('訓練完畢,寫入模型...')for k, v in feature_word_count.items():scores = [(v[i] + 1) * 1.0 / (feature_doc_words_count[i] + len(feature_word_count)) for i in range(len(v))]out_model.write(k + '\t' + str(scores) + '\n') def load_model(model_file):"""從模型文件中導入計算好的貝葉斯模型:param model_file::return:"""print('加載模型中...')with open(model_file, encoding='utf-8') as f:scores = {}for line in f.readlines():word, counts = line.split('\t', 1)scores[word] = eval(counts)return scores(4)預測
def predict(feature_file, model_file, test_text):"""預測文檔的類別,標準輸入每一行為一個文檔這是一個樸素貝葉斯的預測方法p(c|x) 正比于 p(c)p(x1|c)....p(xn|c):param feature_file::param model_file::param test_text::return:"""doc_words_count, features = load_feature_words(feature_file)# p(c)doc_scores = [math.log(count * 1.0 / sum(doc_words_count)) for count in doc_words_count]scores = load_model(model_file)r_count = 0doc_count = 0print("正在使用測試數據驗證模型效果...")for line in test_text:label, text = line.strip().split(' ', 1)int_label = int(label)words = text.split(' ')pre_values = list(doc_scores)for word in words:if word in features:for i in range(len(pre_values)):pre_values[i] += math.log(scores[word][i])m = max(pre_values)p_index = pre_values.index(m)if p_index == int_label:r_count += 1doc_count += 1print("總共測試文本量: %d ,預測正確的類別量:%d,樸素貝葉斯分類器準確度:%f" %(doc_count, r_count, r_count * 1.0 / doc_count))(5)測試
if __name__ == '__main__':out_in_file = 'd:/nlps/result.txt'out_feature_file = 'd:/nlps/feature.txt'out_model_file = 'd:/nlps/model.txt'train_text, test_text = shuffle(out_in_file)count_for_cates(train_text, out_feature_file)train_bayes(out_feature_file, train_text, out_model_file)predict(out_feature_file, out_model_file, test_text)(6)測試結果
周志華 《機器學習》 4.2節 ??
Bishop “Pattern Recognition and Machine Learning” 1.6.1 ??
寒小陽 ??
總結
以上是生活随笔為你收集整理的朴素Bayse新闻分类实践的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [源码学习]--UGUI
- 下一篇: 静态方法工厂模式