機器學習實戰:樸素貝葉斯--學習筆記
阿新 • • 發佈:2018-12-16
一、工作原理
- 我們用 p1(x,y) 表示資料點 (x,y) 屬於類別 1的概率,用 p2(x,y) 表示資料點 (x,y) 屬於類別 2的概率;
那麼對於一個新資料點 (x,y),可以用下面的規則來判斷它的類別:
如果 p1(x,y) > p2(x,y) ,那麼類別為1
如果 p2(x,y) > p1(x,y) ,那麼類別為2關鍵則在於計算資料點屬於不同類別的概率,再取概率最大的概率對應的類別作為預測類別
二、例項程式碼(python 3)
1. 過濾網站惡意留言
from numpy import *
#過濾網站的惡意留言
# 建立一個實驗樣本
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]
return postingList, classVec
# 建立一個包含在所有文件中出現的不重複詞的列表
def createVocabList(dataSet) :
vocabSet = set([]) #建立一個空集
for document in dataSet:
vocabSet = vocabSet | set(document) #建立兩個集合的並集
return list(vocabSet)
#將文件詞條轉換成詞向量
def setOfWords2Vec(vocabList, inputSet):
returnVec = [0]*len(vocabList) #建立一個其中所含元素都為0的向量
for word in inputSet:
if word in vocabList:
#returnVec[vocabList.index(word)] = 1 #index函式在字串裡找到字元第一次出現的位置 詞集模型
returnVec[vocabList.index(word)] += 1 #文件的詞袋模型 每個單詞可以出現多次
else: print('the word: %s is not in my vocabulary' % word)
return returnVec
if __name__ == '__main__':
postingList, classVec = loadDataSet()
print('postingList:\n',postingList)
myVocabList = createVocabList(postingList)
print('myVocabList:\n',myVocabList)
trainMat = []
for postinDoc in postingList:
trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
print('trainMat:\n', trainMat)
依據給定詞得出分類結果
from numpy import *
import numpy as np
#過濾網站的惡意留言
# 建立一個實驗樣本
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]
return postingList, classVec
# 建立一個包含在所有文件中出現的不重複詞的列表
def createVocabList(dataSet):
vocabSet = set([]) #建立一個空集
for document in dataSet:
vocabSet = vocabSet | set(document) #建立兩個集合的並集
return list(vocabSet)
#將文件詞條轉換成詞向量
def setOfWords2Vec(vocabList, inputSet):
returnVec = [0]*len(vocabList) #建立一個其中所含元素都為0的向量
for word in inputSet:
if word in vocabList:
#returnVec[vocabList.index(word)] = 1 #index函式在字串裡找到字元第一次出現的位置 詞集模型
returnVec[vocabList.index(word)] += 1 #文件的詞袋模型 每個單詞可以出現多次
else: print('the word: %s is not in my vocabulary' % word)
return returnVec
def train_naive_bayes(train_mat, train_category):
"""
樸素貝葉斯分類修正版, 注意和原來的對比,為什麼這麼做可以檢視書
:param train_mat: type is ndarray
總的輸入文字,大致是 [[0,1,0,1], [], []]
:param train_category: 檔案對應的類別分類, [0, 1, 0],
列表的長度應該等於上面那個輸入文字的長度
:return:
"""
train_doc_num = len(train_mat)
words_num = len(train_mat[0])
# 因為侮辱性的被標記為了1, 所以只要把他們相加就可以得到侮辱性的有多少
# 侮辱性檔案的出現概率,即train_category中所有的1的個數,
# 代表的就是多少個侮辱性檔案,與檔案的總數相除就得到了侮辱性檔案的出現概率
pos_abusive = np.sum(train_category) / train_doc_num
# 單詞出現的次數
# 原版,變成ones是修改版,這是為了防止數字過小溢位
# p0num = np.zeros(words_num)
# p1num = np.zeros(words_num)
p0num = np.ones(words_num)
p1num = np.ones(words_num)
# 整個資料集單詞出現的次數(原來是0,後面改成2了)
p0num_all = 2.0
p1num_all = 2.0
for i in range(train_doc_num):
# 遍歷所有的檔案,如果是侮辱性檔案,就計算此侮辱性檔案中出現的侮辱性單詞的個數
if train_category[i] == 1:
p1num += train_mat[i]
p1num_all += np.sum(train_mat[i])
else:
p0num += train_mat[i]
p0num_all += np.sum(train_mat[i])
# 後面改成取 log 函式
p1vec = np.log(p1num / p1num_all)
p0vec = np.log(p0num / p0num_all)
return p0vec, p1vec, pos_abusive
def classify_naive_bayes(vec2classify, p0vec, p1vec, p_class1):
"""
使用演算法:
# 將乘法轉換為加法
乘法:P(C|F1F2...Fn) = P(F1F2...Fn|C)P(C)/P(F1F2...Fn)
加法:P(F1|C)*P(F2|C)....P(Fn|C)P(C) -> log(P(F1|C))+log(P(F2|C))+....+log(P(Fn|C))+log(P(C))
:param vec2classify: 待測資料[0,1,1,1,1...],即要分類的向量
:param p0vec: 類別0,即正常文件的[log(P(F1|C0)),log(P(F2|C0)),log(P(F3|C0)),log(P(F4|C0)),log(P(F5|C0))....]列表
:param p1vec: 類別1,即侮辱性文件的[log(P(F1|C1)),log(P(F2|C1)),log(P(F3|C1)),log(P(F4|C1)),log(P(F5|C1))....]列表
:param p_class1: 類別1,侮辱性檔案的出現概率
:return: 類別1 or 0
"""
# 計算公式 log(P(F1|C))+log(P(F2|C))+....+log(P(Fn|C))+log(P(C))
# 使用 NumPy 陣列來計算兩個向量相乘的結果,這裡的相乘是指對應元素相乘,即先將兩個向量中的第一個元素相乘,然後將第2個元素相乘,以此類推。
# 我的理解是:這裡的 vec2Classify * p1Vec 的意思就是將每個詞與其對應的概率相關聯起來
# 可以理解為 1.單詞在詞彙表中的條件下,檔案是good 類別的概率 也可以理解為 2.在整個空間下,檔案既在詞彙表中又是good類別的概率
p1 = np.sum(vec2classify * p1vec) + np.log(p_class1)
p0 = np.sum(vec2classify * p0vec) + np.log(1 - p_class1)
if p1 > p0:
return 1
else:
return 0
if __name__ == '__main__':
"""
測試樸素貝葉斯演算法
:return: no return
"""
# 1. 載入資料集
list_post, list_classes = loadDataSet()
# 2. 建立單詞集合
vocab_list = createVocabList(list_post)
# 3. 計算單詞是否出現並建立資料矩陣
train_mat = []
for post_in in list_post:
train_mat.append(
# 返回m*len(vocab_list)的矩陣, 記錄的都是0,1資訊
# 其實就是那個東西的句子向量(就是data_set裡面每一行,也不算句子吧)
setOfWords2Vec(vocab_list, post_in)
)
# 4. 訓練資料
p0v, p1v, p_abusive = train_naive_bayes(np.array(train_mat), np.array(list_classes))
# 5. 測試資料
test_one = ['love', 'my', 'dalmation']
test_one_doc = np.array(setOfWords2Vec(vocab_list, test_one))
print('the result is: {}'.format(classify_naive_bayes(test_one_doc, p0v, p1v, p_abusive)))
test_two = ['stupid', 'garbage']
test_two_doc = np.array(setOfWords2Vec(vocab_list, test_two))
print('the result is: {}'.format(classify_naive_bayes(test_two_doc, p0v, p1v, p_abusive)))