《機器學習實戰》筆記(三):樸素貝葉斯
4.1 基於貝葉斯決策理論的分類方法
樸素貝葉斯是貝葉斯決策理論的一部分,貝葉斯決策理論的的核心思想,即選擇具有最高概率的決策。若p1(x,y)和p2(x,y)分別代表資料點(x,y)屬於類別1,2的概率,則判斷新資料點(x,y)屬於哪一類別的規則是:
4.3 使用條件概率來分類
在實際問題中,我們真正需要計算和比較的是
和
。這些符號代表的意思是:資料點(x,y)來自c1和c2的概略分別是多少。其中,
4.4 使用樸素貝葉斯進行文件分類
4.5 使用python進行文字分類
文字的特徵來自文字的詞條(token),一個詞條可以使單詞,url或其他任意字元。將每一個文字片段表示為一個詞條向量,其中1表示詞條出現在文件中,0表示詞條未出現。
以線上社群的留言板為例。為了不影響社群的發展,因此要遮蔽侮辱性言論,所以要構建一個過濾器。當留言使用了侮辱性言論,則將留言標識為內容不當。對此問題建立兩個類別:侮辱類和非侮辱類,使用1和0表示。
4.5.1 準備資料:從文字中構建詞向量
在此步,我們要將句子轉化為向量。考慮文件中出現的所有單詞,整合成詞彙表,然後將每一篇文件轉換為詞彙表上的向量。首先,建立檔案bayes.py,新增程式。
import numpy as np
# 4-1 詞表到向量的轉換函式
# 建立實驗資料集
def loadDataSet():
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'],
['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],
['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']]
classVec = [0,1,0,1,0,1] # 1代表侮辱性文字 0 代表正常言論 類別標籤的集合
return postingList,classVec
# 根據實驗資料集,生成詞彙表
def createVocabList(dataSet):
vocabSet = set([]) # 建立空集
for document in dataSet:
vocabSet = vocabSet | set(document) # 集合去重,合併兩個集合
return list(vocabSet) # 返回詞彙表
# 輸入引數:詞彙表及某個文件 輸出:文件向量
def setOfWord2Vec(vocabList, inputSet):
returnVec = [0]*len(vocabList) # 建立一個所含元素都為0的向量
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
listOPosts, listClasses = loadDataSet()
myVocabList = createVocabList(listOPosts)
print(myVocabList)
print(setOfWord2Vec(myVocabList, listOPosts[0]))
假設文字已切分完,存放於列表中。函式loadDataSet()建立了一些實驗樣本,其將返回實驗資料集和類別標籤的集合。createVocabList()將會建立一個包含postingList出現的不重複詞的列表,獲得詞彙表後,便可以使用函式setOfWords2Vec(),該函式的輸入引數為詞彙表及某個文件,輸出的是文件向量,向量的每一元素為1或0,分別表示詞彙表中的單詞在輸入文件中是否出現。
程式執行結果:
4.5.2 訓練演算法:從詞向量計算概率
前面我們將一組單詞轉換為一組數字,接下來我們用這些數字計算概率。設w表示一個向量,它由多個數值組成,數值個數與詞彙表中的詞個數相同。
使用上述公式計算一條留言屬於類別1或0的概率,然後比較兩個值的大小,即可判斷某條留言的類別。其中
計算
,這裡假設
相互獨立,則
則程式4-2程式碼如下:
def trainNB0(trainMatrix, trainCategory):
numTrainDocs = len(trainMatrix) # 訓練文件數
numWords = len(trainMatrix[0]) # 總詞數
pAbusive = sum(trainCategory)/float(numTrainDocs) # 計算文件屬於侮辱性文件的概率
p0Num = np.zeros(numWords)
p1Num = np.zeros(numWords)
p0Denom = 0.0; p1Denom = 0.0
for i in range(numTrainDocs):
if trainCategory[i] == 1:
p1Num += trainMatrix[i]
p1Denom += sum(trainMatrix[i])
else:
p0Num += trainMatrix[i]
p0Denom += sum(trainMatrix[i])
p1Vect = p1Num/p1Denom # 對每個元素做除法
p0Vect = p0Num/p0Denom
return p0Vect,p1Vect,pAbusive
listOPosts, listClasses = loadDataSet()
myVocabList = createVocabList(listOPosts)
print(myVocabList)
trainMat = []
# 構建訓練矩陣
for postinDoc in listOPosts:
trainMat.append(setOfWord2Vec(myVocabList, postinDoc))
p0V, p1V, pAb = trainNB0(trainMat, listClasses)
print("p0V:\n", p0V)
print("p1v:\n", p1V)
print("pAb:", pAb)
執行程式,結果如下:
其中cute在第四個位置,其只在類別0中出現一次,對應條件概率分別為0.0.4166667和0.0。
4.5.3 測試演算法:修改分類器
因為
若其中一個概率值為0,最後乘積為0,所以將所有詞出現次數初始化為1,並將分母初始化為2。
由於大部分因子都非常小,很可能經四捨五入後得到0,所以對乘積取自然對數。所以修改return前兩行程式碼:
構建分類函式,新增到bayes.py檔案中,
# 程式4-3 樸素貝葉斯分類函式
'''
輸入:要分類的向量vec2Classify,使用trainNB0()計算得到的三個概率
'''
def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
p1 = sum(vec2Classify * p1Vec) + np.log(pClass1) # 元素相乘
p0 = sum(vec2Classify * p0Vec) + np.log(1 - pClass1)
if p1 > p0:
return 1
else:
return 0
def testingNB():
listOPosts, listClasses = loadDataSet()
myVocabList = createVocabList(listOPosts)
trainMat = []
for postinDoc in listOPosts:
trainMat.append(setOfWord2Vec(myVocabList, postinDoc))
p0V,p1V,pAb = trainNB0(np.array(trainMat),np.array(listClasses))
testEntry = ['love', 'my', 'dalmation']
thisDoc = np.array(setOfWord2Vec(myVocabList, testEntry))
print(testEntry, "classified as:", classifyNB(thisDoc,p0V, p1V, pAb))
testEntry = ['stupid', 'garbage']
thisDoc = np.array(setOfWord2Vec(myVocabList, testEntry))
print(testEntry, "classified as:", classifyNB(thisDoc, p0V, p1V, pAb))
testingNB()
執行程式:
4.5.4 準備資料:文件詞袋模型
上述程式中,我們使用了詞集模型(set-of-words model),即每個詞的出現與否作為一個特徵。
**詞袋模型(bag-of-words model)**中,每個單詞可以出現多次,因此將詞集模型程式碼修改為詞袋模型的程式碼:
# 詞袋模型
def bagOfWord2Vec(vocabList, inputSet):
returnVec = [0] * len(vocabList) # 建立一個所含元素都為0的向量
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] += 1
return returnVec
4.6 示例:使用樸素貝葉斯過濾垃圾郵件
程式碼例項:
#coding=utf-8
_date_ = '2018/11/20 20:01'
_author_ = 'Cxy'
# 郵件過濾例項
import numpy as np
import random
# 根據實驗資料集,生成詞彙表
def createVocabList(dataSet):
vocabSet = set([]) # 建立空集
for document in dataSet:
vocabSet = vocabSet | set(document) # 集合去重,合併兩個集合
return list(vocabSet) # 返回詞彙表
# 詞集模型 輸入引數:詞彙表及某個文件 輸出:文件向量
def setOfWord2Vec(vocabList, inputSet):
returnVec = [0]*len(vocabList) # 建立一個所含元素都為0的向量
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 bagOfWord2Vec(vocabList, inputSet):
returnVec = [0] * len(vocabList) # 建立一個所含元素都為0的向量