一、樸素貝葉斯介紹
??前兩章我們要求分類器做出艱難決策,給出“該數(shù)據(jù)實(shí)例屬于哪一類”這類問題的明確答案。不過,分類器有時(shí)會(huì)產(chǎn)生錯(cuò)誤結(jié)果,這時(shí)可以要求分類器給出一個(gè)最優(yōu)的類別猜測結(jié)果,同時(shí)給出這個(gè)猜測的概率估計(jì)值。
??樸素貝葉斯(Naive Bayesian)算法能夠根據(jù)數(shù)據(jù)加先驗(yàn)概率來估計(jì)后驗(yàn)概率,在垃圾郵件分類、文本分類、信用等級評定等多分類問題中得到廣泛應(yīng)用。樸素貝葉斯算法以自變量之間的獨(dú)立性和連續(xù)變量的正態(tài)性假設(shè)為前提,會(huì)導(dǎo)致算法精度在一定程度上受到影響。


二、樸素貝葉斯理論
1、貝葉斯決策理論
假設(shè)現(xiàn)在我們有一個(gè)數(shù)據(jù)集,它由兩類數(shù)據(jù)組成,數(shù)據(jù)分布如下圖所示:

??我們現(xiàn)在用 p1(x,y) 表示數(shù)據(jù)點(diǎn)(x,y)屬于類別1(圖中用圓點(diǎn)表示的類別)的概率,用 p2(x,y) 表示數(shù)據(jù)點(diǎn)(x,y)屬于類別2(圖中用三角形表示的類別)的概率,那么對于一個(gè)新數(shù)據(jù)點(diǎn)(x,y),可以用下面的規(guī)則來判斷它的類別:
??如果 p1(x,y) > p2(x,y) ,那么類別為1。
??如果 p2(x,y) > p1(x,y) ,那么類別為2。
??也就是說,我們會(huì)選擇高概率對應(yīng)的類別。這就是貝葉斯決策理論的核心思想,即選擇具有最高概率的決策。
2、條件概率
??條件概率(Condittional probability)是指在事件B發(fā)生的情況下,事件A發(fā)生的概率,用P(A|B)來表示。


3、全概率公式
??假定樣本空間S,是兩個(gè)事件A與A'的和。紅色部分是事件A,綠色部分是事件A',它們共同構(gòu)成了樣本空間S。

??在這種情況下,事件B可以劃分成兩個(gè)部分。


??得到了條件概率的另一種寫法:

4、貝葉斯推斷
??對條件概率公式進(jìn)行變形,可以得到如下形式:

??我們把P(A)稱為"先驗(yàn)概率"(Prior probability),即在B事件發(fā)生之前,我們對A事件概率的一個(gè)判斷。
??P(A|B)稱為"后驗(yàn)概率"(Posterior probability),即在B事件發(fā)生之后,我們對A事件概率的重新評估。
??P(B|A)/P(B)稱為"可能性函數(shù)"(Likelyhood),這是一個(gè)調(diào)整因子,使得預(yù)估概率更接近真實(shí)概率。
??所以,條件概率可以理解成: 后驗(yàn)概率=先驗(yàn)概率x調(diào)整因子,這就是貝葉斯推斷的含義。
??我們先預(yù)估一個(gè)"先驗(yàn)概率",然后加入實(shí)驗(yàn)結(jié)果,看這個(gè)實(shí)驗(yàn)到底是增強(qiáng)還是削弱了"先驗(yàn)概率",由此得到更接近事實(shí)的"后驗(yàn)概率"。如果"可能性函數(shù)"P(B|A)/P(B)>1,意味著"先驗(yàn)概率"被增強(qiáng),事件A的發(fā)生的可能性變大;如果"可能性函數(shù)"=1,意味著B事件無助于判斷事件A的可能性;如果"可能性函數(shù)"<1,意味著"先驗(yàn)概率"被削弱,事件A的可能性變小。
??舉個(gè)例子,從下圖中計(jì)算從A桶中取到黑色石頭的概率。

??H1表示A桶,H2表示B桶。由于這兩個(gè)桶是一樣的,被選中的概率都一樣,所以P(H1)=P(H2)=0.5,我們把這個(gè)概率就叫做"先驗(yàn)概率",即沒有做實(shí)驗(yàn)之前,來自A桶的概率是0.5。假定,E表示黑色石頭,所以問題變成了在已知E的情況下,來自A桶的概率有多大,即求P(H1|E)。我們把這個(gè)概率叫做"后驗(yàn)概率",即在E事件發(fā)生之后,對P(H1)的修正。


??這表明,來自A的概率是3/5。也就是說,取出黑色石頭之后,H1事件的可能性得到了增強(qiáng)。
5、樸素貝葉斯推斷

??貝葉斯和樸素貝葉斯的概念是不同的,區(qū)別就在于“樸素”二字,樸素貝葉斯對條件個(gè)概率分布做了條件獨(dú)立性的假設(shè)。 比如下面的公式,假設(shè)有n個(gè)特征:

??由于每個(gè)特征都是獨(dú)立的,我們可以進(jìn)一步拆分公式 :

三、樸素貝葉斯完成文檔分類
貼上第三、第四節(jié)的全部代碼:
# -*- coding: UTF-8 -*-
from numpy import *
import re
import feedparser
def loadDataSet():
"""
Function:
創(chuàng)建實(shí)驗(yàn)樣本
Parameters:
無
Returns:
postingList - 實(shí)驗(yàn)樣本切分的原始詞條列表,列表每一行代表一個(gè)文檔
classVec - 類別標(biāo)簽向量
Modify:
2018-08-11
"""
postingList = [['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'],
['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'],
['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'],
['stop', 'posting', 'stupid', 'worthless', 'garbage'],
['my', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],
['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']]
classVec = [0, 1, 0, 1, 0, 1]
return postingList, classVec
# 統(tǒng)計(jì)所有文檔中出現(xiàn)的詞條列表,即沒有重復(fù)的單詞
def createVocabList(dataSet):
"""
Function:
創(chuàng)建一個(gè)包含在所有文檔中出現(xiàn)的不重復(fù)詞的列表
Parameters:
dataSet - 樣本切分詞條數(shù)據(jù)集
Returns:
vocabSet - 返回不重復(fù)的詞條列表,也就是詞匯表
Modify:
2018-08-11
"""
vocabSet = set([])
for document in dataSet:
# 將文檔列表轉(zhuǎn)為集合的形式,保證每個(gè)詞條的唯一性
# 然后與vocabSet取并集,向vocabSet中添加沒有出現(xiàn)新的詞條
vocabSet = vocabSet | set(document)
return list(vocabSet)
def setOfWords2Vec(vocabList, inputSet):
"""
Function:
根據(jù)詞條列表中的詞條是否在文檔中出現(xiàn)(出現(xiàn)1,未出現(xiàn)0),將文檔轉(zhuǎn)化為詞條向量
Parameters:
vocabList - createVocabList返回的列表
inputSet - 切分的詞條列表
Returns:
returnVec - 文檔向量,詞集模型
Modify:
2018-08-11
"""
returnVec = [0] * len(vocabList)
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] = 1
else:
print('the word: %s is not in my vocabulary!' % word)
return returnVec
# 樸素貝葉斯分類器的訓(xùn)練函數(shù)
def trainNB0(trainMatrix, trainCategory):
"""
Function:
樸素貝葉斯分類器的訓(xùn)練函數(shù)
Parameters:
trainMatrix - 訓(xùn)練文檔矩陣,即setOfWords2Vec返回的returnVec構(gòu)成的矩陣
trainCategory - 訓(xùn)練類別標(biāo)簽向量,即loadDataSet返回的classVec
Returns:
p0Vect - 非侮辱類的條件概率數(shù)組
p1Vect - 侮辱類的條件概率數(shù)組
pAbusive - 文檔屬于侮辱類的概率
Modify:
2018-08-11
"""
numTrainDocs = len(trainMatrix)
numWords = len(trainMatrix[0])
pAbusive = sum(trainCategory) / float(numTrainDocs)
p0Num = ones(numWords)
p1Num = ones(numWords)
# 初始化所有詞出現(xiàn)數(shù)為1,并將分母初始化為2,避免某一個(gè)概率值為0
p0Denom = 2.0
p1Denom = 2.0
for i in range(numTrainDocs):
if trainCategory[i] == 1:
# 統(tǒng)計(jì)屬于侮辱類的條件概率所需的數(shù)據(jù),即P(w0|1),P(w1|1),P(w2|1)...
p1Num += trainMatrix[i]
p1Num += trainMatrix[i]
p1Denom += sum(trainMatrix[i])
else:
# 統(tǒng)計(jì)屬于非侮辱類的條件概率所需的數(shù)據(jù),即P(w0|0),P(w1|0),P(w2|0)···
p0Num += trainMatrix[i]
p0Denom += sum(trainMatrix[i])
# 將結(jié)果取自然對數(shù),避免下溢出,即太多很小的數(shù)相乘造成的影響
p1Vect = log(p1Num / p1Denom)
p0Vect = log(p0Num / p0Denom)
return p0Vect, p1Vect, pAbusive
# 樸素貝葉斯分類函數(shù)
def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
"""
Function:
樸素貝葉斯分類函數(shù)
Parameters:
vec2Classify - 待分類的詞條數(shù)組
p0Vec - 侮辱類的條件概率數(shù)組
p1Vec -非侮辱類的條件概率數(shù)組
pClass1 - 文檔屬于侮辱類的概率
Returns:
0 - 屬于非侮辱類
1 - 屬于侮辱類
Modify:
2018-08-15
"""
p1 = sum(vec2Classify * p1Vec) + log(pClass1)
p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1)
if p1 > p0:
return 1
else:
return 0
def testingNB():
"""
Function:
樸素貝葉斯分類測試函數(shù)
Parameters:
無
Returns:
無
Modify:
2018-08-15
"""
listOPosts, listClasses = loadDataSet()
myVocabList = createVocabList(listOPosts)
trainMat = []
for postinDoc in listOPosts:
trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
p0V, p1V, pAb = trainNB0(trainMat, array(listClasses))
# 測試文檔
testEntry = ['love', 'my', 'dalmation']
# 將測試文檔轉(zhuǎn)為詞條向量,并轉(zhuǎn)為NumPy數(shù)組的形式
thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
# 利用貝葉斯分類函數(shù)對測試文檔進(jìn)行分類并打印
print(testEntry, 'classified as:', classifyNB(thisDoc, p0V, p1V, pAb))
# 第二個(gè)測試文檔
testEntry1 = ['stupid', 'garbage']
# 同樣轉(zhuǎn)為詞條向量,并轉(zhuǎn)為NumPy數(shù)組的形式
thisDoc1 = array(setOfWords2Vec(myVocabList, testEntry1))
print(testEntry1, 'classified as:', classifyNB(thisDoc1, p0V, p1V, pAb))
def bagOfWords2VecMN(vocabList, inputSet):
"""
Function:
樸素貝葉斯詞袋模型,根據(jù)詞條列表中的詞條是否在文檔中出現(xiàn)(出現(xiàn)1,未出現(xiàn)0),將文檔轉(zhuǎn)化為詞條向量
Parameters:
vocabList - createVocabList返回的列表
inputSet - 切分的詞條列表
Returns:
returnVec - 文檔向量,詞集模型
Modify:
2018-08-15
"""
returnVec = [0] * len(vocabList)
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] += 1
else:
print('the word: %s is not in my vocabulary!' % word)
return returnVec
def textParse(bigString):
"""
Function:
將大字符串其解析為字符串列表
Parameters:
bigString - 郵件字符串
Returns:
tok - 字符串列表
Modify:
2018-08-15
"""
# 對長字符串進(jìn)行分割,分隔符為除單詞和數(shù)字之外的任意符號串
listOfTokens = re.split(r'\W*', bigString)
# 將分割后的字符串中所有的大些字母變成小寫lower(), 并且只保留單詞長度大于3的單詞
return [tok.lower() for tok in listOfTokens if len(tok) > 2]
def spamTest():
"""
Function:
使用樸素貝葉斯過濾垃圾郵件測試函數(shù)
Parameters:
無
Returns:
無
Modify:
2018-08-15
"""
docList = []
classList = []
fullText = []
for i in range(1, 26):
wordList = textParse(
open('D:/PycharmProjects/Machine/machinelearninginaction/Ch04/email/spam/%d.txt' % i).read())
docList.append(wordList)
fullText.extend(wordList)
classList.append(1)
wordList = textParse(
open('D:/PycharmProjects/Machine/machinelearninginaction/Ch04/email/ham/%d.txt' % i).read())
docList.append(wordList)
fullText.extend(wordList)
classList.append(0)
vocabList = createVocabList(docList)
trainingSet = list(range(50))
testSet = []
# 選10組做測試集,根據(jù)隨機(jī)產(chǎn)生索引值獲取
for i in range(10):
randIndex = int(random.uniform(0, len(trainingSet)))
testSet.append(trainingSet[randIndex])
del (trainingSet[randIndex])
trainMat = []
trainClasses = []
# 生成訓(xùn)練矩陣及標(biāo)簽
for docIndex in trainingSet:
trainMat.append(bagOfWords2VecMN(vocabList, docList[docIndex]))
trainClasses.append(classList[docIndex])
p0V, p1V, pSpam = trainNB0(array(trainMat), array(trainClasses))
errorCount = 0
# 測試并計(jì)算錯(cuò)誤率
for docIndex in testSet:
wordVector = bagOfWords2VecMN(vocabList, docList[docIndex])
if classifyNB(array(wordVector), p0V, p1V, pSpam) != classList[docIndex]:
errorCount += 1
print("分類錯(cuò)誤的測試集:", docList[docIndex])
print('the error rate is: ', float(errorCount) / len(testSet))
if __name__ == '__main__':
# postingList, classVec = loadDataSet()
# for each in postingList:
# print(each)
# print(classVec)
# myVocabList = createVocabList(postingList)
# print('詞匯表:', myVocabList)
# trainMat = []
# for postinDoc in postingList:
# trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
# print('詞條向量:', trainMat)
#
# p0Vect, p1Vect, pAbusive = trainNB0(trainMat, classVec)
# print('p0V:\n', p0Vect)
# print('p1V:\n', p1Vect)
# print('classVec:\n', classVec)
# print('pAb:\n', pAbusive)
# testingNB()
spamTest()
spamTest()

??以在線社區(qū)的留言板為例。為了不影響社區(qū)的發(fā)展,我們要屏蔽侮辱性的言論,所以要構(gòu)建一個(gè)快速過濾器,如果某條留言使用了負(fù)面或者侮辱性的語言,那么就將該留言標(biāo)識為內(nèi)容不當(dāng)。過濾這類內(nèi)容是一個(gè)很常見的需求。對此問題建立兩個(gè)類別:侮辱類和非侮辱類,使用1和0分別表示。
(1)創(chuàng)建實(shí)驗(yàn)樣本

(2)構(gòu)建詞條向量

(3)分類器訓(xùn)練

??利用貝葉斯分類器對文檔進(jìn)行分類時(shí),要計(jì)算多個(gè)概率的乘積以獲得文檔屬于某個(gè)類別的概
率,即計(jì)算 p(w 0 |1)p(w 1 |1)p(w 2 |1) 。如果其中一個(gè)概率值為0,那么最后的乘積也為0。為降低這種影響,可以將所有詞的出現(xiàn)數(shù)初始化為1,并將分母初始化為2。
??另一個(gè)遇到的問題是下溢出,這是由于太多很小的數(shù)相乘造成的。當(dāng)計(jì)算乘積
p(w 0 |c i )p(w 1 |c i )p(w 2 |c i )...p(w N |c i ) 時(shí),由于大部分因子都非常小,所以程序會(huì)下溢出或者得到不正確的答案。一種解決辦法是對乘積取自然對數(shù)。在代數(shù)中有 ln(a*b) = ln(a)+ln(b) ,于是通過求對數(shù)可以避免下溢出或者浮點(diǎn)數(shù)舍入導(dǎo)致的錯(cuò)誤。同時(shí),采用自然對數(shù)進(jìn)行處理不會(huì)有任何損失。
(4)樸素貝葉斯分類函數(shù)測試

(5)使用文檔詞袋模型完善樸素貝葉斯分類器
??前面我們將每個(gè)詞的出現(xiàn)與否作為一個(gè)特征,這可以被描述為詞集模型(set-of-words model)。如果一個(gè)詞在文檔中出現(xiàn)不止一次,這可能意味著包含該詞是否出現(xiàn)在文檔中所不能表達(dá)的某種信息,這種方法被稱為詞袋模型(bag-of-words model)。在詞袋中,每個(gè)單詞可以出現(xiàn)多次,而在詞集中,每個(gè)詞只能出現(xiàn)一次。為適應(yīng)詞袋模型,需要對函數(shù) setOfWords2Vec()稍加修改,修改后的函數(shù)稱為bagOfWords2VecMN() 。
四、示例:使用樸素貝葉斯過濾垃圾郵件

??函數(shù) spamTest() 會(huì)輸出在10封隨機(jī)選擇的電子郵件上的分類錯(cuò)誤率。既然這些電子郵件是隨機(jī)選擇的,所以每次的輸出結(jié)果可能有些差別。如果發(fā)現(xiàn)錯(cuò)誤的話,函數(shù)會(huì)輸出錯(cuò)分文檔的詞表,這樣就可以了解到底是哪篇文檔發(fā)生了錯(cuò)誤。如果想要更好地估計(jì)錯(cuò)誤率,那么就應(yīng)該將上述過程重復(fù)多次,比如說10次,然后求平均值。
五、應(yīng)用scikit-learn實(shí)現(xiàn)新浪新聞分類
??1、中文語句切分
??英文的語句可以通過非字母和非數(shù)字進(jìn)行切分,同樣地,漢語句子也可以直接使用第三方分詞組件jieba進(jìn)行切分。可以在cmd命令行下用pip install jieba命令進(jìn)行安裝即可。新浪新聞數(shù)據(jù)集已經(jīng)做好分類,分文件夾保存,分類結(jié)果如下:



??紅色框上邊還有很多沒顯示出來。
??2、文本特征選擇
??將所有文本分成訓(xùn)練集和測試集,并對訓(xùn)練集中的所有單詞進(jìn)行詞頻統(tǒng)計(jì),并按降序排序。也就是將出現(xiàn)次數(shù)多的詞語在前,出現(xiàn)次數(shù)少的詞語在后進(jìn)行排序。

??觀察一下打印結(jié)果,不難發(fā)現(xiàn),里包含了很多標(biāo)點(diǎn)符號,很顯然這些標(biāo)點(diǎn)符號是不能作為新聞分類的特征的。為了降低這些高頻的符號對分類結(jié)果的影響,應(yīng)該要?jiǎng)h除他們。
??除了這些,還有"在","了"等這樣無關(guān)痛癢的詞,還有一些數(shù)字,數(shù)字顯然也不能作為分類新聞的特征。所以要消除它們對分類結(jié)果的影響,我們可以定制一個(gè)規(guī)則:首先去掉高頻詞,至于去掉多少個(gè)高頻詞,我們可以通過觀察去掉高頻詞個(gè)數(shù)和最終檢測準(zhǔn)確率的關(guān)系來確定。除此之外,去除數(shù)字,不把數(shù)字作為分類特征。同時(shí),去除一些特定的詞語,比如:"的","一","在","不","當(dāng)然","怎么"這類的對新聞分類無影響的介詞、代詞、連詞。

??現(xiàn)在看到已經(jīng)濾除了那些沒有用的詞組了。這個(gè)featureWords就是我們最終選出的用于新聞分類的特征。
??3、使用Sklearn構(gòu)建樸素貝葉斯分類器
??相對于決策樹,KNN之類的算法,樸素貝葉斯需要關(guān)注的參數(shù)是比較少的,是一類比較簡單的算法。在scikit-learn中,一共有3個(gè)樸素貝葉斯的分類算法類,分別是GaussianNB,MultinomialNB和BernoulliNB。其中GaussianNB是先驗(yàn)為高斯分布的樸素貝葉斯,MultinomialNB是先驗(yàn)為多項(xiàng)式分布的樸素貝葉斯,BernoulliNB是先驗(yàn)為伯努利分布的樸素貝葉斯。
??對于新聞分類,屬于多分類問題??梢允褂肕ultinamialNB()完成我們的新聞分類問題。
??貼上代碼:
import os
import jieba
import random
from sklearn.naive_bayes import MultinomialNB
import matplotlib.pyplot as plt
def textProcessing(folderPath, testSize=0.2):
"""
Function:
中文文本處理
Parameters:
folderPath - 文本存放的路徑
testSize - 測試集占比,默認(rèn)占所有數(shù)據(jù)集的百分之20
Returns:
allWordsList - 按詞頻降序排序的訓(xùn)練集列表
trainDataList - 訓(xùn)練集列表
testDataList - 測試集列表
trainClassList - 訓(xùn)練集標(biāo)簽列表
testClassList - 測試集標(biāo)簽列表
Modify:
2018-08-22
"""
folderList = os.listdir(folderPath)
dataList = []
classList = []
# for folder in folderList[0:1]:
for folder in folderList:
newFolderList = os.path.join(folderPath, folder)
files = os.listdir(newFolderList)
# print(files)
j = 1
for file in files:
if j > 100:
break
with open(os.path.join(newFolderList, file), 'r', encoding='utf-8') as f:
raw = f.read()
# 精簡模式,返回一個(gè)可迭代的generator
wordCut = jieba.cut(raw, cut_all=False)
# generator轉(zhuǎn)換為list
wordList = list(wordCut)
# 添加數(shù)據(jù)集數(shù)據(jù)
dataList.append(wordList)
# 添加數(shù)據(jù)集類別
classList.append(folder)
j += 1
# zip()將對象中對應(yīng)的元素打包成一個(gè)個(gè)元組
dataClassList = list(zip(dataList, classList))
# 將data_class_list亂序
random.shuffle(dataClassList)
# 訓(xùn)練集和測試集切分的索引值
index = int(len(dataClassList) * testSize) + 1
trainList = dataClassList[index:]
testList = dataClassList[:index]
# 與 zip 相反,*zipped 可理解為解壓,返回二維矩陣式
trainDataList, trainClassList = zip(*trainList)
testDataList, testClassList = zip(*testList)
allWordsDict = {}
for wordList in trainDataList:
for word in wordList:
if word in allWordsDict.keys():
allWordsDict[word] += 1
else:
allWordsDict[word] = 1
# dict.items()函數(shù)以列表返回可遍歷的(鍵, 值)元組數(shù)組
# 根據(jù)鍵的值倒序排序
allWordsTupleList = sorted(allWordsDict.items(), key=lambda f: f[1], reverse=True)
allWordsList, allWordsNums = zip(*allWordsTupleList)
allWordsList = list(allWordsList)
return allWordsList, trainDataList, testDataList, trainClassList, testClassList
def makeWordsSet(wordsPath):
"""
Function:
讀取文件里的內(nèi)容,并去重
Parameters:
folderPath - 文件路徑
Returns:
wordsSet - 讀取的內(nèi)容的set集合
Modify:
2018-08-22
"""
wordsSet = set()
with open(wordsPath, 'r', encoding='utf-8') as f:
for line in f.readlines():
word = line.strip()
if len(word) > 0:
wordsSet.add(word)
return wordsSet
def wordsDict(allWordsList, deleteN, stopWordsSet=set()):
"""
Function:
文本特征選取
Parameters:
allWordsList - 按詞頻降序排序的訓(xùn)練集所有文本列表
deleteN - 刪除詞頻最高的deleteN個(gè)詞
Returns:
featureWords - 特征集
Modify:
2018-08-22
"""
featureWords = []
n = 1
for t in range(deleteN, len(allWordsList), 1):
if n > 1000:
break
if not allWordsList[t].isdigit() and allWordsList[t] not in stopWordsSet and 1 < len(allWordsList[t]) < 5:
featureWords.append(allWordsList[t])
n += 1
return featureWords
def matrixFeatures(trainDataList, testDataList, featureWords):
"""
Function:
根據(jù)feature_words將文本向量化
Parameters:
trainDataList - 訓(xùn)練集
testDataList - 測試集
featureWords - 特征集
Returns:
trainFeatureList - 訓(xùn)練集向量化列表
testFeatureList - 測試集向量化列表
Modify:
2018-08-22
"""
def matrixFeature(text, featureWords):
textWords = set(text)
# 出現(xiàn)在特征集中,則置1
features = [1 if word in textWords else 0 for word in featureWords]
return features
trainFeatureList = [matrixFeature(text, featureWords) for text in trainDataList]
testFeatureList = [matrixFeature(text, featureWords) for text in testDataList]
return trainFeatureList, testFeatureList
def sinaNewsClassifier(trainFeatureList, testFeatureList, trainClassList, testClassList):
classifier = MultinomialNB().fit(trainFeatureList, trainClassList)
testAccuracy = classifier.score(testFeatureList, testClassList)
return testAccuracy
if __name__ == '__main__':
folderPath = './machinelearninginaction/Ch04/SogouC/Sample'
# textProcessing(folderPath)
allWordsList, trainDataList, testDataList, trainClassList, testClassList = textProcessing(folderPath)
stopWordsFile = './machinelearninginaction/Ch04/SogouC/stopwords_cn.txt'
stopWordsSet = makeWordsSet(stopWordsFile)
# featureWords = wordsDict(allWordsList, 100, stopWordsSet)
# print(featureWords)
testAccuracyList = []
deleteNs = range(0, 1000, 20)
for deleteN in deleteNs:
featureWords = wordsDict(allWordsList, deleteN, stopWordsSet)
trainFeatureList, testFeatureList = matrixFeatures(trainDataList, testDataList, featureWords)
testAccuracy = sinaNewsClassifier(trainFeatureList, testFeatureList, trainClassList, testClassList)
testAccuracyList.append(testAccuracy)
plt.figure()
plt.plot(deleteNs, testAccuracyList)
plt.title('Relationship of deleteNs and test_accuracy')
plt.xlabel('deleteNs')
plt.ylabel('test_accuracy')
plt.show()

??上面繪制出了deleteNs和testAccuracy的關(guān)系,這樣可以大致確定去掉前多少的高頻詞匯了。每次運(yùn)行程序,繪制的圖形可能不一定相同。
六、小結(jié)
??樸素貝葉斯算法是建立在每一個(gè)特征值之間時(shí)獨(dú)立的基礎(chǔ)上的監(jiān)督學(xué)習(xí)分類算法,而這也是稱他為 “樸素”貝葉斯的緣由,在現(xiàn)實(shí)環(huán)境中,很難達(dá)到兩個(gè)特征值之間絕對的相互獨(dú)立。