1. 程式人生 > >[西瓜書]樸素貝葉斯--numpy + python實現

[西瓜書]樸素貝葉斯--numpy + python實現

貝葉斯定理

現在假設有兩個事件分別為A和B,貝葉斯定理則可以描述在事件A發生的前提下B發生的概率以及在事件B發生的前提下事件A發生的概率之間的關係。有點繞?畫個圖就能理解了~

這裡寫圖片描述

現在假設事件A發生的概率為 P(A) 事件B發生的概率為 P(B) ,事件A和B同時發生的概率為 P(C) 。事件A發生的前提下B發生的概率就是 P(B|A)=P(C)P(A) ,在事件B發生的前提下A發生的概率為 P

(A|B)=P(C)P(B) 。那麼這兩者之間存在什麼樣的關係呢?通過簡單的變換我們可以得到下面的等式:

P(B|A)P(A)=P(A|B)P(B)

==>P(A|B)=P(A)P(B|A)P(B)
上述的公式就是貝葉斯公式。推到過程是不是很簡單~

樸素貝葉斯概率模型

基本思想

回到分類的問題上,我們想要通過上面的公式解決具體的分類問題。首先,我們根據一般的分類問題將上面公式中提到的A和B具體化一下,我們指示A為樣本,其包含樣本所有的特徵資料。B為分類的類別。為更好的對對應起來,我們用x代指一個樣本資料,c代表一個分類類別。那麼就有如下的貝葉斯公式:

P(c|x)=P(c)P(x|c)P(x)
這個公式的左邊描述的是,在我們已知一個數據樣本的情況下,其歸屬類別c的概率。很自然的我們就可以想到,將資料x和類別對應的一一計算,分別計算該樣本在被分類到不同類別的概率,找到概率最大的那個類別,就是我們將要分類的類別了。

問題簡化

確定解決的方向之後,因為需要實際的解決問題,我們當然希望計算的過程越簡單越好,所以我們需要對問題模型進行適當的處理,而又儘量的保持原方法的理論準確率。

簡化公式

公式方面,我們觀察到P(x)和類別沒有關係,也就是說對於任何類別的概率計算,p(x)都是一個常數,並不會影響最終的結果。所以我們可以將其從公式中刪除掉,簡化後得到下面的公式:

P(c|x)=P(c)P(x|c)

簡化模型

從上面簡化之後的公式中我們可以看出,其和聯合分佈其實有點類似

p(c,x1,x2...xn)=p(x1,x2..xn|c)p(c)=p(x2..xn|c,x1)p(c)p(x1|c)......
在實際情況中,如果考慮特徵之間的關聯性。我們通常沒有辦法直接計算 p(x1,x2..xn|n) ,即使通過上面聯合分佈的公式處理依舊非常的複雜也有可能沒辦法計算結果。所以,這裡為了方便計算,我們需要對模型進行簡化,在世界的計算過程中我們忽略特徵之間的額相關性,雖然他它們之間的相關性大多數時候是存在的。

這樣忽略屬性之間的相關性在周老師的書中被稱之為“屬性條件獨立性假設(attribute conditional independence assumption)”。基於這樣的前提,我們繼續使用聯絡分佈公式,以第二個等式為例:

p(x1,x2..xn|c)p(c)=p(x2..xn|c,x1)p(c)p(x1|c)=p(x2,..xn|c)p(c)p(x1|c)
繼續分解下去我們可以得到
P(c|x)=P(c)P(x|c)=p(c)p(x1,x2,x3..xn|c)=p(c)p(x1|c)p(x2|c)p(x3|c)....p(xn|c)=p(c)i=1np(xi|c)

通過上面最後一個公式,我們可以很方便的計算出在已知一個樣本的情況下,其歸屬於不同類別的概率。

那現在就讓我們來程式設計實現一下吧:

python實現

"""
樸素貝葉斯
    基於貝葉斯公式,並添加了屬性條件獨立性假設。
"""

import numpy as np
from sklearn.datasets import load_iris

iris = load_iris()  # 載入資料
y = iris.target
x = iris.data


def naive_bayes(x, y, predict):
    unique_y = list(set(y))
    label_num = len(unique_y)
    sample_num, dim = x.shape
    joint_p = [1] * label_num
    # 把所有的類別都過一遍,計算P(c)
    for (label_index, label) in enumerate(unique_y):
        p_c = len(y[y == label]) / sample_num
        for (feature_index, x_i) in enumerate(predict):
            tmp = x[y == label]
            joint_p[label_index] *= len(
            [t for t in tmp[:, feature_index] if t == x_i]) / len(tmp)
        joint_p[label_index] *= p_c

    tmp = joint_p[0]
    max_index = 0
    for (i, p) in enumerate(joint_p):
        if tmp < p:
            tmp = p
            max_index = i

    return unique_y[max_index]

# 測試所用的資料為資料集中最後一個數據,類別為2
out = naive_bayes(x, y, np.array([5.9, 3., 5.1, 1.8]))
print(out)

好了大功告成~希望對大家有幫助~