1. 程式人生 > >機器學習實戰:樸素貝葉斯--學習筆記

機器學習實戰:樸素貝葉斯--學習筆記

一、工作原理

  1. 我們用 p1(x,y) 表示資料點 (x,y) 屬於類別 1的概率,用 p2(x,y) 表示資料點 (x,y) 屬於類別 2的概率;
  2. 那麼對於一個新資料點 (x,y),可以用下面的規則來判斷它的類別:

    如果 p1(x,y) > p2(x,y) ,那麼類別為1
    如果 p2(x,y) > p1(x,y) ,那麼類別為2

  3. 關鍵則在於計算資料點屬於不同類別的概率,再取概率最大的概率對應的類別作為預測類別

二、例項程式碼(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)))

三、參考資料