貝葉斯機器學習:經典模型與代碼實現

貝葉斯定理是概率模型中最著名的理論之一,在機器學習中也有着廣泛的應用。基於貝葉斯理論常用的機器學習概率模型包括樸素貝葉斯和貝葉斯網絡。本章在對貝葉斯理論進行簡介的基礎上,分別對樸素貝葉斯和貝葉斯網絡理論進行詳細的推導並給出相應的代碼實現,針對樸素貝葉斯模型,本章給出其 NumPy 和 sklearn 的實現方法,而貝葉斯網絡的實現則是藉助於 pgmpy。

貝葉斯理論簡介

自從 Thomas Bayes 於 1763 年發表了那篇著名的《論有關機遇問題的求解》一文後,以貝葉斯公式爲核心的貝葉斯理論自此發展起來。貝葉斯理論認爲任意未知量都可以看作爲一個隨機變量,對該未知量的描述可以用一個概率分佈來概括,這是貝葉斯學派最基本的觀點。當這個概率分佈在進行現場試驗或者抽樣前就已確定,便可將該分佈稱之爲先驗分佈,再結合由給定數據集 X 計算樣本的似然函數後,即可應用貝葉斯公式計算該未知量的後驗概率分佈。經典的貝葉斯公式表達如下:

上式左邊爲後驗分佈,右邊分母爲邊緣分佈,其排除了任何有關未知量的信息,因此貝葉斯公式的等價形式可以寫作爲:

              

上式可以歸納出貝葉斯公式的本質就是基於先驗分佈和似然函數的統計推斷。其中先驗分佈的選擇與後驗分佈的推斷是貝葉斯領域的兩個核心問題。先驗分佈的選擇目前並沒有統一的標準,不同的先驗分佈對後驗計算的準確度有很大的影響,這也是貝葉斯領域的研究熱門之一;後驗分佈曾因複雜的數學形式和高維數值積分使得後驗推斷十分困難,而後隨着計算機技術的發展,基於計算機軟件的數值技術使得這些問題得以解決,貝葉斯理論又重新煥發活力。

與機器學習的結合正是貝葉斯理論的主要應用方向。樸素貝葉斯理論是一種基於貝葉斯理論的概率分類模型,而貝葉斯網絡是一種將貝葉斯理論應用到概率圖中的分類模型。

樸素貝葉斯原理與推導

樸素貝葉斯是基於貝葉斯定理和特徵條件獨立假設的分類算法。具體而言,對於給定的訓練數據,樸素貝葉斯先基於特徵條件獨立假設學習輸入和輸出的聯合概率分佈,然後對於新的實例,利用貝葉斯定理計算出最大的後驗概率。樸素貝葉斯不會直接學習輸入輸出的聯合概率分佈,而是通過學習類的先驗概率和類條件概率來完成。樸素貝葉斯的概率計算公式如圖 1 所示。

圖 1 樸素貝葉斯基本公式

樸素貝葉斯中樸素的含義,即特徵條件獨立假設,條件獨立假設就是說用於分類的特徵在類確定的條件下都是條件獨立的,這一假設使得樸素貝葉斯的學習成爲可能。假設輸入特徵向量爲 X,輸出爲類標記隨便變量 Y,P(X,Y) 爲 X 和 Y 的聯合概率分佈,T 爲給定訓練數據集。樸素貝葉斯基於訓練數據集來學習聯合概率分佈 P(X,Y)。具體地,通過學習類先驗概率分佈和類條件概率分佈來實現。

樸素貝葉斯學習步驟如下。先計算類先驗概率分佈:

其中 Ck 表示第 k 個類別,yi 表示第 i 個樣本的類標記。類先驗概率分佈可以通過極大似然估計得到。

然後計算類條件概率分佈:

 

直接對 P(X=x|Y=Ck) 進行估計不太可行,因爲參數量太大。但是樸素貝葉斯的一個最重要的假設就是條件獨立性假設,即:

有了條件獨立性假設之後,便可基於極大似然估計計算類條件概率。

類先驗概率分佈和類條件概率分佈都計算得到之後,基於貝葉斯公式即可計算類後驗概率:

代入類條件計算公式,有:

基於上式即可學習一個樸素貝葉斯分類模型。給定新的數據樣本時,計算其最大後驗概率即可:

其中,分母對於所有的都是一樣的,所以上式可進一步簡化爲:

 

以上就是樸素貝葉斯分類模型的簡單推導過程。

基於 NumPy 的樸素貝葉斯實現

本節我們基於 NumPy 來實現一個簡單樸素貝葉斯分類器。樸素貝葉斯因爲條件獨立性假設變得簡化,所以實現思路也較爲簡單,這裏我們就不給出實現的思維導圖了。根據前述推導,關鍵在於使用極大似然估計方法計算類先驗概率分佈和類條件概率分佈。

我們直接定義樸素貝葉斯模型訓練過程,如代碼 1 所示。

def nb_fit(X, y):
    classes = y[y.columns[0]].unique()
    class_count = y[y.columns[0]].value_counts()
    class_prior = class_count/len(y)
    prior = dict()
    for col in X.columns:
        for j in classes:
            p_x_y = X[(y==j).values][col].value_counts()
            for i in p_x_y.index:
                prior[(col, i, j)] = p_x_y[i]/class_count[j]
    return classes, class_prior, prior

在代碼 1 中,給定數據輸入和輸出均爲 Pandas 數據框格式,先對標籤類別數量進行統計,並以此基於極大似然估計計算類先驗分佈。然後對數據特徵和類別進行循環遍歷,計算類條件概率。

式(10)作爲樸素貝葉斯的核心公式,接下來我們需要基於式(10)和 nb_fit 函數返回的類先驗概率和類條件概率來編寫樸素貝葉斯的預測函數。樸素貝葉斯的預測函數如代碼 2 所示。

def predict(X_test):
    res = []
    for c in classes:
        p_y = class_prior[c]
        p_x_y = 1
        for i in X_test.items():
            p_x_y *= prior[tuple(list(i)+[c])]
        res.append(p_y*p_x_y)
    return classes[np.argmax(res)]

代碼 2 中定義了樸素貝葉斯的預測函數。以測試樣本 X_test 作爲輸入,初始化結果列表並獲取當前類的先驗概率,對測試樣本字典進行遍歷,先計算類條件概率的連乘,然後計算先驗概率與類條件概率的乘積。最後按照式(21.10)取 argmax 獲得最大後驗概率所屬的類別。

最後,我們使用數據樣例對編寫的樸素貝葉斯代碼進行測試。手動創建一個二分類的示例數據,並對其使用 nb_fit 進行訓練,如代碼 3 所示。

### 創建數據集並訓練
# 特徵X1
x1 = [1,1,1,1,1,2,2,2,2,2,3,3,3,3,3]
# 特徵X2
x2 = ['S','M','M','S','S','S','M','M','L','L','L','M','M','L','L']
# 標籤列表
y = [-1,-1,1,1,-1,-1,-1,1,1,1,1,1,1,1,-1]
# 形成一個pandas數據框
df = pd.DataFrame({'x1':x1, 'x2':x2, 'y':y})
# 獲取訓練輸入和輸出
X, y = df[['x1', 'x2']], df[['y']]
# 樸素貝葉斯模型訓練
classes, class_prior, prior_condition_prob = nb_fit(X, y)
print(classes, class_prior, prior_condition_prob)

圖 2 代碼 21-3 輸出截圖

在代碼 3 中,我們基於列表構建了 Pandas 數據框格式的數據集,獲取訓練輸入和輸出並傳入樸素貝葉斯訓練函數中,輸出結果如圖 21.2 所示。可以看到,數據標籤包括是 1/-1 的二分類數據集,類先驗概率分佈爲 {1:0.6,-1:0.4},各類條件概率如圖中所示。

最後,我們創建一個測試樣本,並基於 nb_predict 函數對其進行類別預測,如下所示。

### 樸素貝葉斯模型預測
X_test = {'x1': 2, 'x2': 'S'}
print('測試數據預測類別爲:', nb_predict(X_test))

輸出:

測試數據預測類別爲:-1

最後模型將該測試樣本預測爲負類。

基於 sklearn 的樸素貝葉斯實現

sklearn 也提供了樸素貝葉斯的算法實現方式,sklearn 爲我們提供了不同似然函數分佈的樸素貝葉斯算法實現方式。比如高斯樸素貝葉斯、伯努利樸素貝葉斯、多項式樸素貝葉斯等。我們以高斯樸素貝葉斯爲例,高斯樸素貝葉斯即假設似然函數爲正態分佈的樸素貝葉斯模型。高斯樸素貝葉斯的似然函數如下式所示。

sklearn 中高斯樸素貝葉斯的調用接口爲 sklearn.naive_bayes.GaussianNB,以 iris 數據集爲例給出調用示例,如代碼 4 所示。

### sklearn高斯樸素貝葉斯示例# 導入相關庫from sklearn.datasets import load_irisfrom sklearn.model_selection import train_test_splitfrom sklearn.naive_bayes import GaussianNBfrom sklearn.metrics import accuracy_score# 導入數據集X, y = load_iris(return_X_y=True)# 數據集劃分X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, random_state=0)# 創建高斯樸素貝葉斯實例gnb = GaussianNB()# 模型擬合併預測y_pred = gnb.fit(X_train, y_train).predict(X_test)print("Accuracy of GaussianNB in iris data test:", accuracy_score(y_test, y_pred))

輸出:

Accuracy of GaussianNB in iris data test:0.9466666666666667

在代碼 4 中,先導入 sklearn 中樸素貝葉斯相關模塊,導入 iris 數據集並進行訓練測試劃分。然後創建高斯樸素貝葉斯模型實例,基於訓練集進行擬合併對測試集進行預測,最後準確率爲 0.947。

貝葉斯網絡

貝葉斯網絡原理與推導

樸素貝葉斯的最大的特點就是特徵的條件獨立假設,但在現實情況下,條件獨立這個假設通常過於嚴格,在實際中很難成立。特徵之間的相關性限制了樸素貝葉斯的性能,所以本節我們將繼續介紹一種放寬了條件獨立假設的貝葉斯算法,即貝葉斯網絡(bayesian network)。

我們先以一個例子進行引入。假設我們需要通過頭像真實性、粉絲數量和動態更新頻率來判斷一個微博賬號是否爲真實賬號。各特徵屬性之間的關係如圖 3 所示。

圖 3 微博賬號屬性關係

圖 3 是一個有向無環圖(directed acyclic graph,DAG),每個節點表示一個特徵或者隨機變量,特徵之間的關係則是用箭頭連線來表示,比如說動態的更新頻率、粉絲數量和頭像真實性都會對一個微博賬號的真實性有影響,而頭像真實性又對粉絲數量有一定影響。但僅有各特徵之間的關係還不足以進行貝葉斯分析。除此之外,貝葉斯網絡中每個節點還有一個與之對應的概率表。假設賬號是否真實和頭像是否真實有如下概率表:

 

圖 4 貝葉斯網絡概率表

圖 4 是體現頭像和賬號是否真實的概率表。第一張概率表表示的是賬號是否真實,因爲該節點沒有父節點,可以直接用先驗概率來表示,表示賬號真實與否的概率。第二張概率表表示的是賬號真實性對於頭像真實性的條件概率。比如說在頭像爲真實頭像的條件下,賬號爲真的概率爲 0.88。在有了 DAG 和概率表之後,我們便可以利用貝葉斯公式進行定量的因果關係推斷。假設我們已知某微博賬號使用了虛假頭像,那麼其賬號爲虛假賬號的概率可以推斷爲:

利用貝葉斯公式,我們可知在虛假頭像的情況下其賬號爲虛假賬號的概率爲 0.345。

通過上面的例子我們直觀的感受到貝葉斯網絡的用法。一個貝葉斯網絡通常由有向無環圖和節點對應的概率表組成。其中 DAG 由節點(node)和有向邊(edge)組成,節點表示特徵屬性或隨機變量,有向邊表示各變量之間的依賴關係。貝葉斯網絡的一個重要性質是:當一個節點的父節點概率分佈確定之後,該節點條件獨立於其所有的非直接父節點。這個性質方便於我們計算變量之間的聯合概率分佈。

一般來說,多變量非獨立隨機變量的聯合概率分佈計算公式如下:

有了節點條件獨立性質之後,上式可以簡化爲:

當由 DAG 表示節點關係和概率表確定後,相關的先驗概率分佈、條件概率分佈就能夠確定,然後基於貝葉斯公式,我們就可以使用貝葉斯網絡進行推斷。

藉助於 pgmpy 的貝葉斯網絡實現

本小節基於 pgmpy 來構造貝葉斯網絡和進行建模訓練。pgmpy 是一款基於 Python 的概率圖模型包,主要包括貝葉斯網絡和馬爾可夫蒙特卡洛等常見概率圖模型的實現以及推斷方法。

我們以學生獲得的推薦信質量的例子來進行貝葉斯網絡的構造。相關特徵之間的 DAG 和概率表如圖 5 所示。

圖 5 推薦信質量的 DAG 和概率表

由圖 5 可知,考試難度、個人聰明與否都會影響到個人成績,另外個人天賦高低也會影響到 SAT 分數,而個人成績好壞會直接影響到推薦信的質量。下面我們直接來用 pgmpy 實現上述貝葉斯網絡模型。

(1)構建模型框架,指定各變量之間的關係。如代碼 5 所示。

# 導入pgmpy相關模塊
from pgmpy.factors.discrete import TabularCPD
from pgmpy.models import BayesianModel
letter_model = BayesianModel([('D', 'G'),
                               ('I', 'G'),
                               ('G', 'L'),
                               ('I', 'S')])

(2)構建各個節點的條件概率分佈,需要指定相關參數和傳入概率表,如代碼 6 所示。

# 學生成績的條件概率分佈
grade_cpd = TabularCPD(
    variable='G', # 節點名稱
    variable_card=3, # 節點取值個數
    values=[[0.3, 0.05, 0.9, 0.5], # 該節點的概率表
    [0.4, 0.25, 0.08, 0.3],
    [0.3, 0.7, 0.02, 0.2]],
    evidence=['I', 'D'], # 該節點的依賴節點
    evidence_card=[2, 2] # 依賴節點的取值個數
)
# 考試難度的條件概率分佈
difficulty_cpd = TabularCPD(
            variable='D',
            variable_card=2,
            values=[[0.6], [0.4]]
)
# 個人天賦的條件概率分佈
intel_cpd = TabularCPD(
            variable='I',
            variable_card=2,
            values=[[0.7], [0.3]]
)
# 推薦信質量的條件概率分佈
letter_cpd = TabularCPD(
            variable='L',
            variable_card=2,
            values=[[0.1, 0.4, 0.99],
            [0.9, 0.6, 0.01]],
            evidence=['G'],
            evidence_card=[3]
)
# SAT考試分數的條件概率分佈
sat_cpd = TabularCPD(
            variable='S',
            variable_card=2,
            values=[[0.95, 0.2],
            [0.05, 0.8]],
            evidence=['I'],
            evidence_card=[2]
)

(3)將各個節點添加到模型中,構建貝葉斯網絡。如代碼 7 所示。

# 將各節點添加到模型中,構建貝葉斯網絡
letter_model.add_cpds(
    grade_cpd, 
    difficulty_cpd,
    intel_cpd,
    letter_cpd,
    sat_cpd
)
# 導入pgmpy貝葉斯推斷模塊
from pgmpy.inference import VariableElimination
# 貝葉斯網絡推斷
letter_infer = VariableElimination(letter_model)
# 天賦較好且考試不難的情況下推斷該學生獲得推薦信質量的好壞
prob_G = letter_infer.query(
            variables=['G'],
            evidence={'I': 1, 'D': 0})
print(prob_G)

輸出如圖 6 所示。

從圖 6 的輸出結果可以看到,當聰明的學生碰上較簡單的考試時,獲得第一等成績的概率高達 90%。

小結

貝葉斯定理是經典的概率模型之一,基於先驗信息和數據觀測得到目標變量的後驗分佈的方式,是貝葉斯的核心理論。貝葉斯理論在機器學習領域也有廣泛的應用,最常用的貝葉斯機器學習模型包括樸素貝葉斯模型和貝葉斯網絡模型。

樸素貝葉斯模型是一種生成學習方法,通過數據學習聯合概率分佈的方式來計算後驗概率分佈。之所以取名爲樸素貝葉斯,是因爲特徵的條件獨立性假設,能夠大大簡化樸素貝葉斯算法的學習和預測過程,但也會帶來一定的精度損失。

進一步地,將樸素貝葉斯的條件獨立假設放寬,認爲特徵之間是存在相關性的貝葉斯模型就是貝葉斯網絡模型。貝葉斯網絡是一種概率無向圖模型,通過有向圖和概率表的方式來構建貝葉斯概率模型。當由有向圖表示節點關係和概率表確定後,相關的先驗概率分佈、條件概率分佈就能夠確定,然後基於貝葉斯公式,就可以使用貝葉斯網絡進行概率推斷。

本文參考代碼地址:

https://github.com/luwill/Machine_Learning_Code_Implementation/tree/master/charpter21_Bayesian_models

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/ALTTA0CZoRD_qHLImgROzQ