柚子快報邀請碼778899分享:人工智能 機器學(xué)習(xí) 貝葉斯分類
一、貝葉斯分類
1.概率論知識
?條件概率的計算公式如下:
P(white|B)=P(white and B)/P(B)
?條件:所有特征之間是條件獨立。 也就是“樸素”。
樸素貝葉斯中的樸素一詞的來源就是假設(shè)各特征之間相互獨立。這一假設(shè)使得樸素貝葉斯算法變得簡單,但有時會犧牲一定的分類準(zhǔn)確率。
2. 貝葉斯公式
? 首先給出貝葉斯公式:
? 換成分類任務(wù)的表達(dá)式:
二、樸素貝葉斯分類器
樸素貝葉斯分類器(Naive?Bayes?Classifier)是一種基于貝葉斯定理和特征條件獨立假設(shè)的分類算法。它被廣泛應(yīng)用于文本分類、垃圾郵件過濾、情感分析等領(lǐng)域。 樸素貝葉斯分類器的原理基于貝葉斯定理,即根據(jù)已知類別的數(shù)據(jù)來估計特征與類別之間的概率分布,然后使用這些概率來對新樣本進(jìn)行分類。 具體地,設(shè)特征向量為?X?=?(x1,?x2,?...,?xn),類別集合為?C?=?{c1,?c2,?...,?ck},我們的目標(biāo)是計算在給定特征向量?X?的條件下,屬于每個類別的概率?P(ci|X),然后選擇具有最大后驗概率的類別作為樣本的分類結(jié)果。
樸素貝葉斯分類器的"樸素"之處在于它假設(shè)特征之間相互獨立,即: ?
其中?P(c_i)?是類別?c_i?的先驗概率,P(X|c_i)?是在類別?c_i?下特征向量?X?的條件概率,P(X)?是特征向量?X?的邊緣概率。由于?P(X)?對所有類別都是相同的,因此可以忽略掉。 基于上述假設(shè),我們可以計算出每個類別的后驗概率,并選擇具有最大概率的類別作為樣本的分類結(jié)果。 樸素貝葉斯分類器的優(yōu)點在于簡單、高效,且對小規(guī)模數(shù)據(jù)表現(xiàn)良好;并且在特征之間條件獨立的情況下,即使部分特征缺失,也能夠進(jìn)行有效的分類。然而,它也有一個明顯的局限性,就是對特征條件獨立的假設(shè)在實際問題中并不總是成立,因此在面對高維度、相關(guān)性較強的數(shù)據(jù)時,樸素貝葉斯分類器可能表現(xiàn)不佳。
三、簡單的案例實現(xiàn)
email文件夾下有兩個文件夾ham和spam。ham文件夾下的txt文件為正常郵件;spam文件下的txt文件為垃圾郵件。
完整代碼:
# -*- coding: UTF-8 -*-
import numpy as np
import re
import random
#整理詞匯表
def createVocabList(dataSet):
vocabSet = set([]) # 創(chuàng)建一個空的不重復(fù)列表
for document in dataSet:
vocabSet = vocabSet | set(document) # 取并集
return list(vocabSet)
def setOfWords2Vec(vocabList, inputSet):
returnVec = [0] * len(vocabList) #創(chuàng)建一個其中所含元素都為0的向量
for word in inputSet: #遍歷每個詞條
if word in vocabList: #如果詞條存在于詞匯表中,則置1
returnVec[vocabList.index(word)] = 1
else:
print("the word: %s is not in my Vocabulary!" % word)
return returnVec #返回文檔向量
#構(gòu)建詞袋模型
def bagOfWords2VecMN(vocabList, inputSet):
returnVec = [0] * len(vocabList) # 創(chuàng)建一個其中所含元素都為0的向量
for word in inputSet: # 遍歷每個詞條
if word in vocabList: # 如果詞條存在于詞匯表中,則計數(shù)加一
returnVec[vocabList.index(word)] += 1
return returnVec # 返回詞袋模型
#樸素貝葉斯分類訓(xùn)練函數(shù)
def trainNB0(trainMatrix, trainCategory):
numTrainDocs = len(trainMatrix) # 計算訓(xùn)練的文檔數(shù)目
numWords = len(trainMatrix[0]) # 計算每篇文檔的詞條數(shù)
pAbusive = sum(trainCategory) / float(numTrainDocs) # 文檔屬于垃圾郵件類的概率
p0Num = np.ones(numWords)
p1Num = np.ones(numWords) # 創(chuàng)建numpy.ones數(shù)組,詞條出現(xiàn)數(shù)初始化為1,拉普拉斯平滑
p0Denom = 2.0
p1Denom = 2.0 # 分母初始化為2 ,拉普拉斯平滑
for i in range(numTrainDocs):
if trainCategory[i] == 1: # 統(tǒng)計屬于侮辱類的條件概率所需的數(shù)據(jù),即P(w0|1),P(w1|1),P(w2|1)···
p1Num += trainMatrix[i]
p1Denom += sum(trainMatrix[i])
else: # 統(tǒng)計屬于非侮辱類的條件概率所需的數(shù)據(jù),即P(w0|0),P(w1|0),P(w2|0)···
p0Num += trainMatrix[i]
p0Denom += sum(trainMatrix[i])
p1Vect = np.log(p1Num / p1Denom)
p0Vect = np.log(p0Num / p0Denom) #取對數(shù),防止下溢出
return p0Vect, p1Vect, pAbusive # 返回屬于正常郵件類的條件概率數(shù)組,屬于侮辱垃圾郵件類的條件概率數(shù)組,文檔屬于垃圾郵件類的概率
#樸素貝葉斯分類函數(shù)
def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
p1=sum(vec2Classify*p1Vec)+np.log(pClass1)
p0=sum(vec2Classify*p0Vec)+np.log(1.0-pClass1)
if p1 > p0:
return 1 #屬于正常郵件類
else:
return 0 #屬于垃圾郵件類
#提取單詞
def textParse(bigString): # 將字符串轉(zhuǎn)換為字符列表
listOfTokens = re.split(r'\W*', bigString) # 將特殊符號作為切分標(biāo)志進(jìn)行字符串切分,即非字母、非數(shù)字
return [tok.lower() for tok in listOfTokens if len(tok) > 2] # 除了單個字母,例如大寫的I,其它單詞變成小寫
#測試樸素貝葉斯分類器,使用樸素貝葉斯進(jìn)行交叉驗證
def spamTest():
docList = []
classList = []
fullText = []
for i in range(1, 21): # 遍歷20個txt文件
wordList = textParse(open('email/spam/%d.txt' % i, 'r').read()) # 讀取每個垃圾郵件,并字符串轉(zhuǎn)換成字符串列表
docList.append(wordList)
fullText.append(wordList)
classList.append(1) # 標(biāo)記垃圾郵件,1表示垃圾文件
wordList = textParse(open('email/ham/%d.txt' % i, 'r').read()) # 讀取每個非垃圾郵件,并字符串轉(zhuǎn)換成字符串列表
docList.append(wordList)
fullText.append(wordList)
classList.append(0) # 標(biāo)記正常郵件,0表示正常文件
vocabList = createVocabList(docList) # 創(chuàng)建詞匯表,不重復(fù)
trainingSet = list(range(50))
testSet = [] # 創(chuàng)建存儲訓(xùn)練集的索引值的列表和測試集的索引值的列表
for i in range(10): # 從50個郵件中,隨機挑選出40個作為訓(xùn)練集,10個做測試集
randIndex = int(random.uniform(0, len(trainingSet))) # 隨機選取索索引值
testSet.append(trainingSet[randIndex]) # 添加測試集的索引值
del (trainingSet[randIndex]) # 在訓(xùn)練集列表中刪除添加到測試集的索引值
trainMat = []
trainClasses = [] # 創(chuàng)建訓(xùn)練集矩陣和訓(xùn)練集類別標(biāo)簽系向量
for docIndex in trainingSet: # 遍歷訓(xùn)練集
trainMat.append(setOfWords2Vec(vocabList, docList[docIndex])) # 將生成的詞集模型添加到訓(xùn)練矩陣中
trainClasses.append(classList[docIndex]) # 將類別添加到訓(xùn)練集類別標(biāo)簽系向量中
p0V, p1V, pSpam = trainNB0(np.array(trainMat), np.array(trainClasses)) # 訓(xùn)練樸素貝葉斯模型
errorCount = 0 # 錯誤分類計數(shù)
for docIndex in testSet: # 遍歷測試集
wordVector = setOfWords2Vec(vocabList, docList[docIndex]) # 測試集的詞集模型
if classifyNB(np.array(wordVector), p0V, p1V, pSpam) != classList[docIndex]: # 如果分類錯誤
errorCount += 1 # 錯誤計數(shù)加1
print("分類錯誤的測試集:", docList[docIndex])
print('錯誤率:%.2f%%' % (float(errorCount) / len(testSet) * 100))
if __name__ == '__main__':
spamTest()
createVocabList?函數(shù)用于創(chuàng)建詞匯表,它接收一個數(shù)據(jù)集并返回數(shù)據(jù)集中所有不重復(fù)單詞的列表。 setOfWords2Vec?函數(shù)將輸入的文本轉(zhuǎn)換為向量,向量的每個元素表示詞匯表中對應(yīng)單詞的出現(xiàn)情況。 bagOfWords2VecMN?函數(shù)構(gòu)建了詞袋模型,與?setOfWords2Vec?類似,但它統(tǒng)計了每個單詞的出現(xiàn)次數(shù)而不是簡單地記錄是否出現(xiàn)。 trainNB0?函數(shù)用于訓(xùn)練樸素貝葉斯分類器,它接收訓(xùn)練數(shù)據(jù)以及對應(yīng)的分類標(biāo)簽,計算每個單詞在不同分類下的條件概率,并返回相應(yīng)的概率向量。 cassifyNB?函數(shù)用于對新的文本進(jìn)行分類,它接收一個文本向量以及訓(xùn)練得到的概率向量和類別概率,然后根據(jù)樸素貝葉斯分類規(guī)則進(jìn)行分類。 textParse?函數(shù)用于將文本解析成單詞列表,同時進(jìn)行了大小寫轉(zhuǎn)換和去除長度小于等于2的單詞等操作。 spamTest?函數(shù)是整個分類器的測試函數(shù),它讀取垃圾郵件和正常郵件的數(shù)據(jù)集,然后進(jìn)行訓(xùn)練和測試,最后輸出分類錯誤率。
四、改進(jìn)思路總結(jié)
1.如何實現(xiàn)多分類
這部分只有二分類,要想多分類就不能只是0與1這么簡單。模型要兼容多分類,可以對結(jié)果集利用np.unique(),然后取出值進(jìn)行分類。特征單個種類分類多,也可以使用這種方法。如果比如身高這些特征符合正態(tài)分布,需要用正態(tài)分布概率進(jìn)行計算。
2.如何提高預(yù)測準(zhǔn)度
2.1、提高訓(xùn)練集數(shù)據(jù)的質(zhì)量?;舅袡C器學(xué)習(xí)對訓(xùn)練集的數(shù)據(jù)要求都很高,貝葉斯更是如此,如果你選取的數(shù)據(jù)質(zhì)量不高,沒有代表性,抽選隨機性不高。對模型影響很大。
2.2、增加訓(xùn)練集的數(shù)量。這個非常好理解,我們投硬幣,投的次數(shù)越多,正面概率越解決1/2。更接近真實值。
2.3、選取特征。我們知道貝葉斯假設(shè)是各個特征獨立,那么我們選取特征的時候盡量不要有冗余,特征之間相關(guān)性不要太大。
? ?
柚子快報邀請碼778899分享:人工智能 機器學(xué)習(xí) 貝葉斯分類
精彩鏈接
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。