1. 程式人生 > >《機器學習實戰》筆記(三):樸素貝葉斯

《機器學習實戰》筆記(三):樸素貝葉斯

4.1 基於貝葉斯決策理論的分類方法

在這裡插入圖片描述
樸素貝葉斯是貝葉斯決策理論的一部分,貝葉斯決策理論的的核心思想,即選擇具有最高概率的決策。若p1(x,y)和p2(x,y)分別代表資料點(x,y)屬於類別1,2的概率,則判斷新資料點(x,y)屬於哪一類別的規則是:
在這裡插入圖片描述

4.3 使用條件概率來分類

在實際問題中,我們真正需要計算和比較的是 p ( c 1

x , y ) p(c_1|x,y) p (
c 2 x , y ) p(c_2|x,y)
。這些符號代表的意思是:資料點(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的概率,然後比較兩個值的大小,即可判斷某條留言的類別。其中
p ( w c i ) = i p(w|c_i)=\frac{類別i中文件數(侮辱性或非侮辱性留言數)}{總的文件數(總留言數)}
計算 p ( w c i ) = p ( w 0 , w 1 , . . , w n c i ) p(w|c_i)=p(w_0,w_1,..,w_n|c_i) ,這裡假設 w 0 , w 1 , . . , w n w_0,w_1,..,w_n 相互獨立,則
p ( w c i ) = p ( w 0 c i ) p ( w 1 c i ) p ( w 2 c i ) . . p ( w n c i ) p(w|c_i)=p(w_0|c_i)p(w_1|c_i)p(w_2|c_i)..p(w_n|c_i)
則程式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 測試演算法:修改分類器

因為 p ( w c i ) = p ( w 0 , w 1 , . . , w n c i ) p(w|c_i)=p(w_0,w_1,..,w_n|c_i) 若其中一個概率值為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的向量