Python的貝葉斯網絡學習庫pgmpy介紹和使用


pgmpy

Parameter learning: Given a set of data samples and a DAG that captures the dependencies between the variables, estimate the (conditional) probability distributions of the individual variables.

Structure learning: Given a set of data samples, estimate a DAG that captures the dependencies between the variables.

pgmpy.org
github.com/pgmpy/pgmpy_notebook/blob/master/blob/master/notebooks

代碼記錄

"""
學習鏈接 :
http://pgmpy.org/
https://github.com/pgmpy/pgmpy_notebook/blob/master/notebooks/9.%20Learning%20Bayesian%20Networks%20from%20Data.ipynb
"""
# ====================BN模型=========================
# 貝葉斯模型
from pgmpy.models import BayesianModel
# ====================參數學習=========================
# 參數估計
from pgmpy.estimators import ParameterEstimator
# MLE參數估計
from pgmpy.estimators import MaximumLikelihoodEstimator
# Bayesian參數估計
from pgmpy.estimators import BayesianEstimator
# ====================結構學習=========================
# ========評分搜索=========================
# 評分
from pgmpy.estimators import BdeuScore, K2Score, BicScore
# 窮舉搜索
from pgmpy.estimators import ExhaustiveSearch
# 爬山搜索
from pgmpy.estimators import HillClimbSearch
# ========  約束  =========================
from pgmpy.estimators import ConstraintBasedEstimator
# 獨立性
from pgmpy.independencies import Independencies
# ========  混合  =========================
from pgmpy.estimators import MmhcEstimator
# ==================== 通用庫 =========================
import pandas as pd
import numpy as np

parameter Learning


def parameterLearning():
    data = pd.DataFrame(data={'fruit': ["banana", "apple", "banana", "apple", "banana","apple", "banana",
                                        "apple", "apple", "apple", "banana", "banana", "apple", "banana",],
                              'tasty': ["yes", "no", "yes", "yes", "yes", "yes", "yes",
                                        "yes", "yes", "yes", "yes", "no", "no", "no"],
                              'size': ["large", "large", "large", "small", "large", "large", "large",
                                        "small", "large", "large", "large", "large", "small", "small"]})
    model = BayesianModel([('fruit', 'tasty'), ('size', 'tasty')])  # fruit -> tasty <- size

    print("========================================================")
    pe = ParameterEstimator(model, data)
    print("\n", pe.state_counts('fruit'))  # unconditional
    print("\n", pe.state_counts('size'))  # unconditional
    print("\n", pe.state_counts('tasty'))  # conditional on fruit and size
    print("========================================================")
    mle = MaximumLikelihoodEstimator(model, data)
    print(mle.estimate_cpd('fruit'))  # unconditional
    print(mle.estimate_cpd('tasty'))  # conditional

    print("========================================================")
    est = BayesianEstimator(model, data)
    print(est.estimate_cpd('tasty', prior_type='BDeu', equivalent_sample_size=10))
    # Setting equivalent_sample_size to 10 means
    # that for each parent configuration, we add the equivalent of 10 uniform samples
    # (here: +5 small bananas that are tasty and +5 that aren't).

    print("========================================================")
    # Calibrate all CPDs of `model` using MLE:
    model.fit(data, estimator=MaximumLikelihoodEstimator)
    print("========================================================")
    # generate data
    data = pd.DataFrame(np.random.randint(low=0, high=2, size=(5000, 4)), columns=['A', 'B', 'C', 'D'])
    model = BayesianModel([('A', 'B'), ('A', 'C'), ('D', 'C'), ('B', 'D')])
    model.fit(data, estimator=BayesianEstimator, prior_type="BDeu") # default equivalent_sample_size=5
    for cpd in model.get_cpds():
        print(cpd)

structural Learning with Score


def structuralLearning_Score():
    """
        score-based structure learning
        constraint-based structure learning
    The combination of both techniques allows further improvement:
        hybrid structure learning
    """
    print("===================基於評分=================================")
    # create random data sample with 3 variables, where Z is dependent on X, Y:
    data = pd.DataFrame(np.random.randint(0, 4, size=(5000, 2)), columns=list('XY'))
    data['Z'] = data['X'] + data['Y']

    bdeu = BdeuScore(data, equivalent_sample_size=5)
    k2 = K2Score(data)
    bic = BicScore(data)

    model1 = BayesianModel([('X', 'Z'), ('Y', 'Z')])  # X -> Z <- Y
    model2 = BayesianModel([('X', 'Z'), ('X', 'Y')])  # Y <- X -> Z
    print("==========基於評分===model1===============")
    print(bdeu.score(model1))
    print(k2.score(model1))
    print(bic.score(model1))
    print("==========基於評分===model2===============")
    print(bdeu.score(model2))
    print(k2.score(model2))
    print(bic.score(model2))
    print("==========基於評分===局部評分==============")
    print(bdeu.local_score('Z', parents=[]))
    print(bdeu.local_score('Z', parents=['X']))
    print(bdeu.local_score('Z', parents=['X', 'Y']))
    print("==========基於評分===窮舉搜索算法==============")
    # 窮舉搜索(計算困難),啓發式搜索
    es = ExhaustiveSearch(data, scoring_method=bic)
    # 獲取分數最高的分數
    best_model = es.estimate()
    print(best_model.edges())
    print("\n 遍歷所有的分數:")
    for score, dag in reversed(es.all_scores()):
        print(score, dag.edges())
    print("==========基於評分===爬山搜索算法==============")
    data = pd.DataFrame(np.random.randint(0, 3, size=(2500, 8)), columns=list('ABCDEFGH'))
    data['A'] += data['B'] + data['C']
    data['H'] = data['G'] - data['A']
    hc = HillClimbSearch(data, scoring_method=BicScore(data))
    best_model = hc.estimate()
    print(best_model.edges())

structural Learning with Constraint


def structuralLearning_Constraint():
    print("===================基於約束=================================")
    # Identify independencies in the data set using hypothesis tests
    # Construct DAG (pattern) according to identified independencies
    data = pd.DataFrame(np.random.randint(0, 3, size=(2500, 8)),
                        columns=list('ABCDEFGH'))
    data['A'] += data['B'] + data['C']
    data['H'] = data['G'] - data['A']
    data['E'] *= data['F']
    # Independencies in the data can be identified
    #       using chi2 conditional independence tests
    est = ConstraintBasedEstimator(data)
    print("==========基於約束===條件獨立測試===============")
    # test_conditional_independence(X, Y, Zs)
    # 判斷X,Y在Zs的條件下是否條件獨立
    # check if X is independent from Y given a set of variables Zs:
    print(est.test_conditional_independence('B', 'H'))  # dependent  False
    print(est.test_conditional_independence('B', 'E'))  # independent   True
    print(est.test_conditional_independence('B', 'H', ['A']))  # independent   True
    print(est.test_conditional_independence('A', 'G'))  # independent   True
    print(est.test_conditional_independence('A', 'G', ['H']))  # dependent   False
    print("==========基於約束===DAG構建=================")
    """
    1. 構造一個無向骨架——estimate_skeleton()
    2. 利用強迫邊進行定向,得到部分有向無環圖(PDAG;- skeleton_to_pdag()
    3. 通過以某種方式保守地定向剩餘的邊,將DAG模式擴展到DAG—pdag_to_dag()
    Step 1.&2. form the so-called PC algorithm.
    PDAGs are DirectedGraphs, that may contain both-way edges, 
        to indicate that the orientation for the edge is not determined.
    """
    skel, seperating_sets = est.estimate_skeleton(significance_level=0.01)
    print("Undirected edges: ", skel.edges())
    pdag = est.skeleton_to_pdag(skel, seperating_sets)
    print("PDAG edges:       ", pdag.edges())
    model = est.pdag_to_dag(pdag)
    print("DAG edges:        ", model.edges())
    print("==========基於約束===DAG構建===estimate方法=================")
    # he estimate()-method provides a shorthand for the three steps above
    #   and directly returns a BayesianModel
    # 三步並作一步,直接返回一個網絡結構
    print(est.estimate(significance_level=0.01).edges())

    print("==========基於約束===DAG構建===從independencies中學習======")
    ind = Independencies(['B', 'C'],
                         ['A', ['B', 'C'], 'D'])
    ind = ind.closure()  # required (!) for faithfulness
    model = ConstraintBasedEstimator.estimate_from_independencies("ABCD", ind)
    print(model.edges())

structural Learning with Hybrid

def structuralLearning_Hybrid():
    """
    MMHC算法[3]結合了基於約束和基於分數的方法。它有兩部分:
        1. 使用基於約束的構造過程MMPC學習無向圖骨架
        2. 基於分數的優化(BDeu分數+修改爬山)
    """
    print("===================混合方法=================================")
    # 實驗數據生成
    data = pd.DataFrame(np.random.randint(0, 3, size=(2500, 8)), columns=list('ABCDEFGH'))
    data['A'] += data['B'] + data['C']
    data['H'] = data['G'] - data['A']
    data['E'] *= data['F']
    # 構建無向圖骨架
    mmhc = MmhcEstimator(data)
    skeleton = mmhc.mmpc()
    print("Part 1) Skeleton: ", skeleton.edges())
    # 基於分數優化
    # use hill climb search to orient the edges:
    hc = HillClimbSearch(data, scoring_method=BdeuScore(data))
    model = hc.estimate(tabu_length=10, white_list=skeleton.to_directed().edges())
    print("Part 2) Model:    ", model.edges())
    print("===================兩步劃爲一步=================================")
    # MmhcEstimator.estimate(self, scoring_method=None, tabu_length=10,
    #       significance_level=0.01)
    # mmhc.estimate(scoring_method=BdeuScore(data),tabu_length=10)

mian

if __name__ == "__main__":
    parameterLearning()
    structuralLearning_Score()
    structuralLearning_Constraint()
    structuralLearning_Hybrid()

運行展示

參數學習

1 ============參數估計=================================================
1 ========state_counts 統計信息=======

         fruit
apple       7
banana      7

        size
large    10
small     4

 fruit apple       banana      
size  large small  large small
tasty                         
no      1.0   1.0    1.0   1.0
yes     3.0   2.0    5.0   0.0
1 ========MLE估計CPD==按變量===========
+---------------+-----+
| fruit(apple)  | 0.5 |
+---------------+-----+
| fruit(banana) | 0.5 |
+---------------+-----+
+------------+--------------+--------------------+---------------------+---------------+
| fruit      | fruit(apple) | fruit(apple)       | fruit(banana)       | fruit(banana) |
+------------+--------------+--------------------+---------------------+---------------+
| size       | size(large)  | size(small)        | size(large)         | size(small)   |
+------------+--------------+--------------------+---------------------+---------------+
| tasty(no)  | 0.25         | 0.3333333333333333 | 0.16666666666666666 | 1.0           |
+------------+--------------+--------------------+---------------------+---------------+
| tasty(yes) | 0.75         | 0.6666666666666666 | 0.8333333333333334  | 0.0           |
+------------+--------------+--------------------+---------------------+---------------+
1 ========貝葉斯估計CPD==按變量========
+------------+---------------------+--------------------+--------------------+---------------------+
| fruit      | fruit(apple)        | fruit(apple)       | fruit(banana)      | fruit(banana)       |
+------------+---------------------+--------------------+--------------------+---------------------+
| size       | size(large)         | size(small)        | size(large)        | size(small)         |
+------------+---------------------+--------------------+--------------------+---------------------+
| tasty(no)  | 0.34615384615384615 | 0.4090909090909091 | 0.2647058823529412 | 0.6428571428571429  |
+------------+---------------------+--------------------+--------------------+---------------------+
| tasty(yes) | 0.6538461538461539  | 0.5909090909090909 | 0.7352941176470589 | 0.35714285714285715 |
+------------+---------------------+--------------------+--------------------+---------------------+
1 ========fit函數估計===所有變量=======
1 ===================================
+------+----------+
| A(0) | 0.506593 |
+------+----------+
| A(1) | 0.493407 |
+------+----------+
+------+--------------------+---------------------+
| A    | A(0)               | A(1)                |
+------+--------------------+---------------------+
| B(0) | 0.5183395779925064 | 0.48076533711277586 |
+------+--------------------+---------------------+
| B(1) | 0.4816604220074936 | 0.5192346628872241  |
+------+--------------------+---------------------+
+------+--------------------+--------------------+---------------------+--------------------+
| A    | A(0)               | A(0)               | A(1)                | A(1)               |
+------+--------------------+--------------------+---------------------+--------------------+
| D    | D(0)               | D(1)               | D(0)                | D(1)               |
+------+--------------------+--------------------+---------------------+--------------------+
| C(0) | 0.5160626836434867 | 0.5142942227516378 | 0.49917576756645377 | 0.4964179104477612 |
+------+--------------------+--------------------+---------------------+--------------------+
| C(1) | 0.4839373163565132 | 0.4857057772483621 | 0.5008242324335462  | 0.5035820895522388 |
+------+--------------------+--------------------+---------------------+--------------------+
+------+--------------------+--------------------+
| B    | B(0)               | B(1)               |
+------+--------------------+--------------------+
| D(0) | 0.5029982010793523 | 0.4918114639504693 |
+------+--------------------+--------------------+
| D(1) | 0.4970017989206476 | 0.5081885360495306 |
+------+--------------------+--------------------+

評分搜索




2 ===================基於評分=================================
2 ==========基於評分===model1===============
-13939.038934816337
-14329.822136429982
-14295.079563299281
2 ==========基於評分===model2===============
-20900.389985754824
-20927.22925737244
-20944.436530518695
2 ==========基於評分===局部評分==============
-9232.535088735991
-6990.879293129073
-57.11895038935745
2 ==========基於評分===窮舉搜索算法==============
[('X', 'Z'), ('Y', 'Z')]

	 遍歷所有的分數:
-14295.079563299281 [('X', 'Z'), ('Y', 'Z')]
-14326.77068416731 [('X', 'Y'), ('Z', 'X'), ('Z', 'Y')]
-14326.770684167312 [('Y', 'X'), ('Z', 'X'), ('Z', 'Y')]
-14326.770684167312 [('Y', 'Z'), ('Y', 'X'), ('Z', 'X')]
-14326.770684167312 [('X', 'Z'), ('Y', 'Z'), ('Y', 'X')]
-14326.770684167312 [('X', 'Y'), ('X', 'Z'), ('Z', 'Y')]
-14326.770684167312 [('X', 'Y'), ('X', 'Z'), ('Y', 'Z')]
-16536.707465219723 [('X', 'Y'), ('Z', 'Y')]
-16537.846854154086 [('Y', 'X'), ('Z', 'X')]
-18701.669239663883 [('Z', 'X'), ('Z', 'Y')]
-18701.669239663883 [('Y', 'Z'), ('Z', 'X')]
-18701.669239663886 [('X', 'Z'), ('Z', 'Y')]
-20911.606020716295 [('Z', 'Y')]
-20911.606020716295 [('Y', 'Z')]
-20912.745409650663 [('Z', 'X')]
-20912.745409650663 [('X', 'Z')]
-20943.297141584328 [('Y', 'X'), ('Z', 'Y')]
-20943.297141584328 [('Y', 'Z'), ('Y', 'X')]
-20943.297141584328 [('X', 'Y'), ('Y', 'Z')]
-20944.436530518695 [('X', 'Z'), ('Y', 'X')]
-20944.436530518695 [('X', 'Y'), ('Z', 'X')]
-20944.436530518695 [('X', 'Y'), ('X', 'Z')]
-23122.682190703075 []
-23154.373311571104 [('Y', 'X')]
-23154.373311571104 [('X', 'Y')]
2 ==========基於評分===爬山搜索算法==============
[('A', 'H'), ('A', 'C'), ('A', 'B'), ('C', 'B'), ('G', 'H')]

約束

3 ===================基於約束=================================
3 ==========基於約束===條件獨立測試===============
False
True
True
True
False
3 ==========基於約束===DAG構建=================
Undirected edges:  [('A', 'B'), ('A', 'C'), ('A', 'H'), ('E', 'F'), ('G', 'H')]
PDAG edges:        [('A', 'H'), ('B', 'A'), ('C', 'A'), ('E', 'F'), ('F', 'E'), ('G', 'H')]
DAG edges:         [('A', 'H'), ('B', 'A'), ('C', 'A'), ('F', 'E'), ('G', 'H')]
3 ==========基於約束===DAG構建===estimate方法=================
[('A', 'H'), ('B', 'A'), ('C', 'A'), ('F', 'E'), ('G', 'H')]
3 ==========基於約束===DAG構建===從independencies中學習======
[('A', 'D'), ('B', 'D'), ('C', 'D')]

混合

4 ===================混合方法=================================
Part 1) Skeleton:  [('A', 'H'), ('A', 'C'), ('E', 'F'), ('G', 'H')]
Part 2) Model:     [('A', 'C'), ('E', 'F'), ('H', 'A'), ('H', 'G')]
4 ===================兩步劃爲一步=================================
。。。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章