天天看點

簡單文檔分類——樸素貝葉斯算法樸素貝葉斯算法簡單文檔分類執行個體步驟總結樸素貝葉斯分類調用(sklearn)

樸素貝葉斯算法

樸素貝葉斯法是基于貝葉斯定理與特征條件獨立假設的分類方法。

最為廣泛的兩種分類模型是決策樹模型(Decision Tree Model)和樸素貝葉斯模型(Naive Bayesian Model,NBM)。和決策樹模型相比,樸素貝葉斯分類器(Naive Bayes Classifier 或 NBC)發源于古典數學理論,有着堅實的數學基礎,以及穩定的分類效率。同時,NBC模型所需估計的參數很少,對缺失資料不太敏感,算法也比較簡單。理論上,NBC模型與其他分類方法相比具有最小的誤差率。但是實際上并非總是如此,這是因為NBC模型假設屬性之間互相獨立,這個假設在實際應用中往往是不成立的,這給NBC模型的正确分類帶來了一定影響。

樸素貝葉斯算法(Naive Bayesian algorithm) 是應用最為廣泛的分類算法之一。

樸素貝葉斯方法是在貝葉斯算法的基礎上進行了相應的簡化,即假定給定目标值時屬性之間互相條件獨立。也就是說沒有哪個屬性變量對于決策結果來說占有着較大的比重,也沒有哪個屬性變量對于決策結果占有着較小的比重。雖然這個簡化方式在一定程度上降低了貝葉斯分類算法的分類效果,但是在實際的應用場景中,極大地簡化了貝葉斯方法的複雜性。

貝葉斯方法

貝葉斯方法是以貝葉斯原理為基礎,使用機率統計的知識對樣本資料集進行分類。由于其有着堅實的數學基礎,貝葉斯分類算法的誤判率是很低的。貝葉斯方法的特點是結合先驗機率和後驗機率,即避免了隻使用先驗機率的主觀偏見,也避免了單獨使用樣本資訊的過拟合現象。貝葉斯分類算法在資料集較大的情況下表現出較高的準确率,同時算法本身也比較簡單。

簡單文檔分類執行個體

import numpy as np

## 簡單文檔分類——樸素貝葉斯算法

'''
建立實驗資料集(假設每個樣本已經被分割完成)
傳回值分别是 X_train, y_train
X_train:表示訓練的樣本
y_train:表示對應訓練樣本的分類結果
'''
def loadDataSet():
    X_train = [
        ['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']
    ]  # 切分好的詞條
    y_train = [0, 1, 0, 1, 0, 1]  # 類别标簽向量,1代表侮辱性詞彙,0代表非侮辱性詞彙
    return X_train, y_train

'''
建立詞彙表
trainData:訓練集trainData(每句話代表一條資料),每句話已被切割成單詞了
vocabList:訓練集中所有的單詞(無重複)
'''
def createVocabList(trainData):
    vocabSet = set()                    # 建立一條空的集合
    # 周遊訓練集dataSet(每句話代表一條資料)中的每句話(已被切割成單詞了)
    for doc in trainData:
        vocabSet = vocabSet | set(doc)  # 取并集,重複的隻記一遍
        # print(vocabSet)
        vocabList = list(vocabSet)
    # print(len(vocabList))
    return vocabList

'''
vocabList:詞彙表
inputSet:目前樣本(話,包含多個已被分割的單詞)
returnVec:傳回每個樣本(話)所對應的結果向量
'''
def setofwords2Vec(vocabList, inputSet):
    returnVec = [0] * len(vocabList)    # 建立詞彙表大小的零向量
    for word in inputSet:   # 周遊目前樣本(話)中的每一個單詞
        if word in vocabList:
            returnVec[vocabList.index(word)] += 1
        else:
            print(f'{word} is not in my vocabulary!')
    return returnVec

'''
生成訓練向量集
dataSet:訓練集
vocabList:詞彙表
trainMat:傳回整個訓練集的結果向量集
        (n*m維,n表示樣本數,m表示詞彙表中詞的個數)
'''
def get_trainMat(dataSet, vocabList):
    trainMat = []   # 初始化向量清單
    for inputSet in dataSet:    # 周遊訓練集中每句話(所有的單詞)
        returnVec = setofwords2Vec(vocabList, inputSet)  # 将目前詞條向量化
        trainMat.append(returnVec)
    return trainMat

'''
拉普拉斯平滑樸素貝葉斯分類器訓練函數
要計算多個機率的乘積以擷取文檔屬于哪個類别,如果其中一個機率為0,則最終計算結果為0,顯然是不合理的。
是以使分子初始化為1,分母初始化為2,這種做法就叫做拉普拉斯平滑,又被稱為加一平滑。它就是為了解決0機率問題
trainMat:訓練結果向量集
classVec:每個訓練樣本的結果向量
'''
def trainNB(trainMat, classVec):
    trainNum = len(trainMat)   # 計算訓練集的數目(總文檔數)
    ClassNum = len(trainMat[0])    # 計算訓練集中每一條的大小(總單詞數)

    p0Num = np.ones(ClassNum)  # 非侮辱類每個單詞詞頻初始化為0,為了防止出現0而初始化為1
    p1Num = np.ones(ClassNum)  # 侮辱類每個單詞詞頻初始化為0,為了防止出現0而初始化為1
    p0Denom = 2  # 非侮辱類所有單詞的詞頻,同理初始化為2
    p1Denom = 2  # 侮辱類所有單詞的詞頻
    num0 = 0    # 各類訓練集個數
    num1 = 0    # 同上

    pNumList = [p0Num, p1Num]
    pDenomList = [p0Denom, p1Denom]
    numList = [num0, num1]

    for i in range(trainNum):  # 周遊每一個訓練樣本
        for j in range(2):  # 周遊每個類别
            if classVec[i] == j:    # 如果第i個訓練樣本為j類樣本
                pNumList[j] += trainMat[i]    # 在該樣本出現的所有單詞詞頻+1
                pDenomList[j] += sum(trainMat[i])     # 同理對分母增加的此樣本所有單詞詞頻
                numList[j] += 1  # 該類文檔數目加1

    # 取log對數仍然是拉普拉斯平滑原理
    pVect, pNum = [], []
    for index in range(2):
        pVect.append(np.log(pNumList[index] / pDenomList[index]))
        pNum.append(numList[index] / float(trainNum))
    return pVect, pNum    # 傳回屬于非侮辱類、侮辱類和整個訓練樣本屬于侮辱類的機率

'''
測試樸素貝葉斯分類器
vec2Classify:向量化的測試樣本
'''
def classifyNB(vec2Classify, pVect, pNum):
    # 計算公式  log(P(F1|C))+log(P(F2|C))+....+log(P(Fn|C))+log(P(C))
    vpl = []  # 文檔分類到各類的機率
    for x in range(2):
        vpl.append(sum(vec2Classify * pVect[x]) + np.log(pNum[x]))

    reslist = ['非侮辱類', '侮辱類']
    index = [vpl.index(res) for res in vpl if res == max(vpl)]
    return reslist[index[0]]    # 傳回分類值

'''
樸素貝葉斯測試函數
'''
def testingNB(testVec):
    dataSet, classVec = loadDataSet()       # 建立實驗樣本
    vocabList = createVocabList(dataSet)    # 建立詞彙表
    trainMat = get_trainMat(dataSet, vocabList)    # 将訓練樣本向量化
    pVect, vpl = trainNB(trainMat, classVec)    # 訓練樸素貝葉斯分類器

    thisone = setofwords2Vec(vocabList, testVec)   # 測試樣本向量化
    return classifyNB(thisone, pVect, vpl)

if __name__  == '__main__':
    # 測試樣本1
    testVec1 = ['love', 'my', 'dalmation']
    print('分類結果是:', testingNB(testVec1))

    # 測試樣本2
    testVec2 = ['stupid', 'garbage']
    print('分類結果是:', testingNB(testVec2))
           

步驟總結

  • 1. 收集資料并預處理

    針對本例來說,省略了收集資料和預處理的大多數步驟。若無則應對訓練集檔案夾内的檔案讀取,并去掉多餘的符号(若有停用詞則删去對應的詞),最後采用分詞如jieba進行切分,然後進行下一步驟。

  • 2. 向量化處理

    将得到的訓練集(和測試集)清單建構不重複的單詞集合,然後向量化每一個樣本清單,建構訓練資料的向量集。

  • 3. 訓練模型

    利用貝葉斯公式計算對應的詞頻進行相應機率計算,注意可能出現0機率現象,是以需要拉普拉斯平滑處理,即特殊初始化操作。

  • 4. 測試驗證模型

    将測試資料同樣進行向量化處理,然後計算每類機率情況,取機率最大值分類即為預測的類别。本例樣本少不再進行驗證準确性。

樸素貝葉斯分類調用(sklearn)

'''以上涉及擷取資料、求詞彙表、求訓練資料集等方法省略,即替代方法trainNB、classifyNB'''

from sklearn.naive_bayes import GaussianNB
from sklearn.naive_bayes import MultinomialNB
from sklearn.naive_bayes import BernoulliNB

'''調用sklearn'''
def sklearnTest(testVec, testDoc):
    # 重複步驟
    dataSet, classVec = loadDataSet()
    vocabList = createVocabList(dataSet)
    trainMat = get_trainMat(dataSet, vocabList)
    testVec = setofwords2Vec(vocabList, testVec)

    X = np.array(trainMat)
    Y = np.array(classVec)
    testVec = np.array(testVec)

    if testDoc == 'GaussianNB':  # 高斯樸素貝葉斯
       clf = GaussianNB()
    elif testDoc == 'MultinomialNB':    # 多項分布貝葉斯
        clf = MultinomialNB()
    elif testDoc == 'BernoulliNB':  # 伯努利分布貝葉斯
        clf = BernoulliNB()
    clf.fit(X, Y)

    # 測試
    input = [testVec]
    index = clf.predict(input)
    resList = ['非侮辱類', '侮辱類']
    return resList[index[0]]

if __name__  == '__main__':
    # 測試樣本1
    testVec1 = ['love', 'my', 'dalmation']
    print('普通樸素貝葉斯分類結果是:', testingNB(testVec1))
    print('高斯樸素貝葉斯分類結果是:', sklearnTest(testVec1, 'GaussianNB'))
    print('多項樸素貝葉斯分類結果是:', sklearnTest(testVec1, 'MultinomialNB'))
    print('伯努利樸素貝葉斯分類結果是:', sklearnTest(testVec1, 'BernoulliNB'))

    # 測試樣本2
    testVec2 = ['stupid', 'garbage']
    print('普通樸素貝葉斯分類結果是:', testingNB(testVec2))
    print('高斯樸素貝葉斯分類結果是:', sklearnTest(testVec2, 'GaussianNB'))
    print('多項樸素貝葉斯分類結果是:', sklearnTest(testVec2, 'MultinomialNB'))
    print('伯努利樸素貝葉斯分類結果是:', sklearnTest(testVec2, 'BernoulliNB'))
           
簡單文檔分類——樸素貝葉斯算法樸素貝葉斯算法簡單文檔分類執行個體步驟總結樸素貝葉斯分類調用(sklearn)
運作結果

參考:樸素貝葉斯算法一步步教你輕松學樸素貝葉斯模型算法Sklearn深度篇3