[機器學習]-朴素貝葉斯-最簡單的入門實戰例子


簡介

 

如果你有一個很大的數據集,有很多的變量,而且已知這是一個分類問題,你想快速的得到你的分類結果,那朴素貝葉斯是一個不錯的選擇,他比一般的分類算法都要快,他的理論基礎是概率中的貝葉斯定理。

本文會介紹朴素貝葉斯的理論基礎,以及一個基於python的實戰例子,so,坐穩了,准備開車

 

 

目錄

 

  1.朴素貝葉斯是如何工作的?

   2.朴素貝葉斯的理論基礎是什么?

   3.朴素貝葉斯的優缺點是什么?

   4.一個實戰例子

   5.使用朴素貝葉斯模型的一些建議

 

 

朴素貝葉斯是如何工作的?

 

接下來用一個簡單的例子介紹,下面的訓練數據集反映了小學生出去玩(Play)和天氣(Weather)之間的關系

 

第一步:將數據集轉換為頻率表

第二步:創建概率表,比如P(sunny) =0.36

    

第三步:用朴素貝葉斯計算后驗概率,后驗概率大的為預測分類(關於先驗概率,后驗概率,看這篇文章

 

問題:根據上面的數據集,如果天氣是sunny就出去玩,這樣說是否正確?

 

可以根據第三步中討論的后驗概率來確定以上說法是否正確。

 

P(Yes | Sunny) = P( Sunny | Yes) * P(Yes) / P (Sunny)    (什么?為什么這樣計算,下面會介紹^_^)

 

P (Sunny |Yes) = 3/9 = 0.33, P(Sunny) = 5/14 = 0.36, P( Yes)= 9/14 = 0.64

 

最后: P (Yes | Sunny) = 0.33 * 0.64 / 0.36 = 0.60,因為0.6>0.5,所以以上說法正確

 

 

朴素貝葉斯的理論基礎是什么?

 

先看看條件獨立公式,如果X和Y相互獨立,則有:

              P(X,Y) = P(X)P(Y)

接着看一下條件概率公式:

              P(Y|X) = P(X,Y)/P(X)

由上面兩個公式可以推出貝葉斯公式:

              P(Y|X) = P(X|Y)P(Y)/P(X)

 

由上面的統計學知識回到我們的數據分析。

 

假設某個體有n項特征(Feature),分別為F1、F2、…、Fn。現有m個類別(Category),分別為C1、C2、…、Cm。貝葉斯分類器就是計算出概率最大的那個分類,也就是求下面這個算式的最大值:

P(C|F1F2...Fn) = P(F1F2...Fn|C)P(C) / P(F1F2...Fn)

由於 P(F1F2…Fn) 對於所有的類別都是相同的,可以省略,問題就變成了求

P(F1F2...Fn|C)P(C)

的最大值。 
朴素貝葉斯分類器則是更進一步,假設所有特征都彼此獨立,因此

P(F1F2...Fn|C)P(C) = P(F1|C)P(F2|C) ... P(Fn|C)P(C)

上式等號右邊的每一項,都可以從統計資料中得到,由此就可以計算出每個類別對應的概率,從而找出最大概率的那個類。 
雖然”所有特征彼此獨立”這個假設,在現實中不太可能成立,但是它可以大大簡化計算,而且有研究表明對分類結果的准確性影響不大。

 

 

朴素貝葉斯的優缺點是什么?

 

優點:

  • 簡單、運算量小、在擁有大量分類的數據集上仍然表現很好
  • 當數據的各個屬性互相獨立的假設成立,朴素貝葉斯比邏輯回歸等模型表現更好,並且朴素貝葉斯需要更少的訓練數據
  • 與數值變量相比,朴素貝葉斯在非數值變量的訓練集上表現更好,因為對於數值型變量,一般假設數據符合正太分布(這個假設是一個很強的假設,大多數數據集並不相符)

缺點:

  • 如果一個變量的某個值在測試集中有,在訓練集中沒有,計算結果將是0概率,無法做出分類,為了解決這個問題,需要引入平滑處理,比較簡單的是拉普拉斯平滑
  • 朴素貝葉斯假定每個變量之間是相互獨立的,但是現實中的數據往往都具有一定的相關性,很少有完全獨立的

 

 

一個實戰例子

 

該例子主要是為了識別某個文本是否具有侮辱性

 

import numpy as np

def getDataSet():
    """
    加載訓練數據, postingList是所有的訓練集, 每一個列表代表一條言論, 一共有8條言論 classVec代表每一條言論的類別,
     0是正常, 1是有侮辱性 返回 言論和類別
    :return:
    """
    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']]
    labels = [0,1,0,1,0,1]
    return postingList,labels

def createVocabList(dataSet):
    """
    創建詞匯表, 就是把這個文檔中所有的單詞不重復的放在一個列表里面
    :param dataSet:
    :return:
    """
    vocabSet = set([])
    for data in dataSet:
        vocabSet = vocabSet | set(data)
    return list(vocabSet)

def vectorize(vocabSet,dataSet):
    """
    制作詞向量矩陣
    將每一個文檔轉換為詞向量, 然后放入矩陣中
    :param vocabSet:
    :param dataSet:
    :return:
    """
    vocab = [0] * len(vocabSet)
    for data in dataSet:
        vocab[vocabSet.index(data)] = 1
    return vocab

def trainN(X_train,y_train):
    """
    制作貝葉斯分類器
    :param X_train:
    :param y_train:
    :return:
    """
    num = len(X_train)   #有多少記錄
    numvocab = len(X_train[0]) #詞向量的大小
    p0Num = np.ones(numvocab) #統計非侮辱類的相關單詞頻數 加入了拉普拉斯平滑
    p1Num = np.ones(numvocab) #統計侮辱類的相關單詞頻數
    p0Sum = 2
    p1Sum = 2
    pA = sum(y_train) / num                   #先驗概率
    for i in range(num):
        if y_train[i]==0:   #統計屬於非侮辱類的條件概率所需的數據
            # p0Sum += sum(X_train[i])
            p0Sum += 1
            p0Num += X_train[i]
        else:               #統計屬於侮辱類的條件概率所需的數據
            # p1Sum += sum(X_train[i])
            p1Sum += 1
            p1Num += X_train[i]

    # 為了防止下溢出,計算條件概率的對數
    p0 = np.log(p0Num / p0Sum)      #頻數除以總數 得到概率
    p1 = np.log(p1Num / p1Sum)
    return p0,p1,pA


def classify(testMat,p0,p1,pA):
    """
    進行分類
    :param testMat: 
    :param p0: 
    :param p1: 
    :param pA: 
    :return: 
    """
    p0Score = sum(testMat * p0) + np.log(pA)
    p1Score = sum(testMat * p1) + np.log(1-pA)
    if p0Score > p1Score:
        return 0
    else:
        return 1

if __name__=='__main__':
    dataSet,label = getDataSet()
    vocabSet = createVocabList(dataSet)
    trainMat = []
    for elem in dataSet:
        trainMat.append(vectorize(vocabSet,elem))
    # print(trainMat)
    p0,p1,pA = trainN(trainMat,label)
    test1= ['love', 'my', 'dalmation']
    test2= ['stupid', 'garbage','love']
    test1_vocab = np.array(vectorize(vocabSet,test1))
    test2_vocab = np.array(vectorize(vocabSet,test2))
    result1 = classify(test1_vocab,p0,p1,pA)
    result2 = classify(test2_vocab,p0,p1,pA)
    if result1==1:
        print(test1,"屬於:侮辱類")
    else:
        print(test1, "屬於:非侮辱類")
    print("------------------------------------------")
    if result2==1:
        print(test2,"屬於:侮辱類")
    else:
        print(test2, "屬於:非侮辱類")

 結果:

['love', 'my', 'dalmation'] 屬於:非侮辱類
------------------------------------------
['stupid', 'garbage', 'love'] 屬於:侮辱類

 

 

 

使用朴素貝葉斯模型的一些建議

 

  • 如果連續型變量不符合正態分布,需要使用一些方法轉換為正太分布
  • 刪除相關屬性,如果相關屬性多次參與計算概率,會導致該屬性出現的概率變大
  • 如果測試數據出現某個變量值在訓練集為0時,記得使用拉普拉斯平滑

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM