Python機器學習算法實作
Author:louwill
在上一講中,我們講到了經典的樸素貝葉斯算法。樸素貝葉斯的一大特點就是特征的條件獨立假設,但在現實情況下,條件獨立這個假設通常過于嚴格,在實際中很難成立。特征之間的相關性限制了樸素貝葉斯的性能,是以本節筆者将繼續介紹一種放寬了條件獨立假設的貝葉斯算法——貝葉斯網絡(Bayesian Network)。
貝葉斯網絡的直覺例子
先以一個例子進行引入。假設我們需要通過頭像真實性、粉絲數量和動态更新頻率來判斷一個微網誌賬号是否為真實賬号。各特征屬性之間的關系如下圖所示:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI0gTMx81dsQWZ4lmZf1GLlpXazVmcvwFciV2dsQXYtJ3bm9CX9s2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xCMy81dvRWYoNHLwEzX5xCMx8FesU2cfdGLwMzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5SN3kzM3gzMzQDNjNmN3gTOyYzXyMzNzYTMyAzLcZDMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.png)
上圖是一個有向無環圖(DAG),每個節點表示一個特征或者随機變量,特征之間的關系則是用箭頭連線來表示,比如說動态的更新頻率、粉絲數量和頭像真實性都會對一個微網誌賬号的真實性有影響,而頭像真實性又對粉絲數量有一定影響。但僅有各特征之間的關系還不足以進行貝葉斯分析。除此之外,貝葉斯網絡中每個節點還有一個與之對應的機率表。
假設賬号是否真實和頭像是否真實有如下機率表:
第一張機率表表示的是賬号是否真實,因為該節點沒有父節點,可以直接用先驗機率來表示,表示賬号真實與否的機率。第二張機率表表示的是賬号真實性對于頭像真實性的條件機率。比如說在頭像為真實頭像的條件下,賬号為真的機率為0.88。在有了DAG和機率表之後,我們便可以利用貝葉斯公式進行定量的因果關系推斷。假設我們已知某微網誌賬号使用了虛假頭像,那麼其賬号為虛假賬号的機率可以推斷為:
利用貝葉斯公式,我們可知在虛假頭像的情況下其賬号為虛假賬号的機率為0.345。
貝葉斯網絡
上面的例子可以讓大家直覺的感受到貝葉斯網絡的作用。一個貝葉斯網絡通常由有向無環圖(DAG)和節點對應的機率表組成。其中DAG由節點(node)和有向邊(edge)組成,節點表示特征屬性或随機變量,有向邊表示各變量之間的依賴關系。貝葉斯網絡的一個重要性質是:當一個節點的父節點機率分布确定之後,該節點條件獨立于其所有的非直接父節點。這個性質友善于我們計算變量之間的聯合機率分布。
一般來說,多變量非獨立随機變量的聯合機率分布計算公式如下:
當有了上述性質之後,該式子就可以簡化為:
基于先驗機率、條件機率分布和貝葉斯公式,我們便可以基于貝葉斯網絡進行機率推斷。
基于pgmpy的貝葉斯網絡實作
本節我們基于pgmpy來構造貝葉斯網絡和進行模組化訓練。pgmpy是一款基于Python的機率圖模型包,主要包括貝葉斯網絡和馬爾可夫蒙特卡洛等常見機率圖模型的實作以及推斷方法。本節使用pgmpy包來實作簡單的貝葉斯網絡。
我們以學生獲得推薦信品質這樣一個例子來進行貝葉斯網絡的構造。具體有向圖和機率表如下圖所示:
考試難度、個人聰明與否都會影響到個人成績,另外個人聰明與否也會影響到SAT分數,而個人成績好壞會直接影響到推薦信的品質。下面我們直接來用pgmpy實作上述貝葉斯網絡。
導入相關子產品:
from pgmpy.factors.discrete import TabularCPD
from pgmpy.models import BayesianModel
構模組化型架構,指定各變量之間的依賴關系:
student_model = BayesianModel([('D', 'G'),
('I', 'G'),
('G', 'L'),
('I', 'S')])
建構各個節點和傳入機率表并指定相關參數:
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_cpd = TabularCPD(
variable='S',
variable_card=2,
values=[[0.95, 0.2],
[0.05, 0.8]],
evidence=['I'],
evidence_card=[2]
)
将包含機率表的各節點添加到模型中:
student_model.add_cpds(
grade_cpd,
difficulty_cpd,
intel_cpd,
letter_cpd,
sat_cpd
)
擷取模型的條件機率分布:
student_model.get_cpds()
擷取模型各節點之間的依賴關系:
student_model.get_independencies()
進行貝葉斯推斷:
from pgmpy.inference import VariableElimination
student_infer = VariableElimination(student_model)
prob_G = student_infer.query(
variables=['G'],
evidence={'I': 1, 'D': 0})
print(prob_G)
可見當聰明的學生碰上較簡單的考試時,獲得第一等成績的機率高達0.9。
除了以上構造貝葉斯網絡的方法之外,我們還可以基于pgmpy進行資料訓練。首先生成模拟資料并以上述的學生推薦信的模型變量進行命名:
# 生成資料
import numpy as np
import pandas as pd
raw_data = np.random.randint(low=0, high=2, size=(1000, 5))
data = pd.DataFrame(raw_data, columns=['D', 'I', 'G', 'L', 'S'])
data.head()
然後基于資料進行模型訓練:
# 定義模型
from pgmpy.models import BayesianModel
from pgmpy.estimators import MaximumLikelihoodEstimator, BayesianEstimator
model = BayesianModel([('D', 'G'), ('I', 'G'), ('I', 'S'), ('G', 'L')])
# 基于極大似然估計進行模型訓練
model.fit(data, estimator=MaximumLikelihoodEstimator)
for cpd in model.get_cpds():
# 列印條件機率分布
print("CPD of {variable}:".format(variable=cpd.variable))
print(cpd)
以上便是基于pgmpy的貝葉斯網絡的簡單實作。關于pgmpy的更多内容,可參考項目位址:
https://github.com/pgmpy/pgmpy
更多内容可參考筆者GitHub位址:
https://github.com/luwill/machine-learning-code-writing
參考資料:
pgmpy: Probabilistic Graphical Models using Python