【转】贝叶斯网络入门教程(原理介绍+python代码实现)

贝叶斯网络原理

贝叶斯网络(Bayesian Network)是一种去除了条件概率独立性的概率图模型,其结构为有向无环图(direct acyclic graph,DAG), 图中每个节点代表一个随机变量,每个节点有对应的概率分布表,有向边表示各节点之间的依赖关系。

局部马尔科夫性
贝叶斯网络的一个性质是局部马尔可夫性。

Assumption 1.1 (Local Markov Assumption) 给定一个节点Χ在有向无环图中的父节点,该节点独立于其所有非后继节点。

对于相互独立的多个变量的联合概率分布,有:

若变量具有局部马尔可夫性,则联合概率分布可简化为:

案例实战

基于pgmpy的python包实现一个用贝叶斯网络进行推理的例子。
安装:

pip install pgmpy

以学生获得推荐信的质量为例,来构造贝叶斯网络。各节点构成的有向无环图和对应的概率表如图所示。从图中可看出推荐信(letter)的质量受到学生成绩(grade)的直接影响,而考试难度(diff)和智力(intel)直接影响学生的成绩。智力还影响SAT的分数。

使用贝叶斯网络推理一个天赋较高的学生在考试较难的情况下获得推荐信的质量的概率分布,步骤如下。
step1: 定义贝叶斯网络结构。

from pgmpy.models import BayesianNetwork
letter_bn=BayesianNetwork([
    ('D','G'),('I','G'),('I','S'),('G','L') # 指向关系 D->I
])

step2: 构建各节点的条件概率分布。

from pgmpy.factors.discrete import TabularCPD
d_cpd=TabularCPD(variable='D',variable_card=2,values=[[0.6],[0.4]])
# 变量名,变量取值个数,对应概率
i_cpd=TabularCPD(variable='I',variable_card=2,values=[[0.7],[0.3]])
g_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]],
 # 行数等于变量取值,列数等于依赖变量总取值数(3,4)
evidence=['I','D'],evidence_card=[2,2]) 
# 变量名,变量取值个数,对应概率,依赖变量名,依赖变量取值
s_cpd=TabularCPD(variable='S',variable_card=2,values=[[0.95,0.2],[0.05,0.8]],
                 evidence=['I'],evidence_card=[2])
l_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]) # evidence_card必须是列表

注意:这里条件概率表的行数等于变量取值,列数等于依赖变量总取值组合数;evidence_card必须是列表。
step3: 添加概率表到贝叶斯网络,检查模型,并输出。

letter_bn.add_cpds(d_cpd,i_cpd,g_cpd,s_cpd,l_cpd)
letter_bn.check_model() # 检查构建的模型是否合理
letter_bn.get_cpds() # 网络中条件概率依赖关系

step4: 利用构建的贝叶斯网络进行具体的推理。这里推断一个天赋较高的学生在考试较难的情况下获得推荐信的质量的概率分布。

from pgmpy.inference import VariableElimination
letter_infer=VariableElimination(letter_bn) # 变量消除
prob_I=letter_infer.query(variables=['L'],evidence={'I':1,'D':1})
print(f"prob_I:{prob_I}")

输出结果如下,可看到得到劣质推荐信的概率为0.368,得到优质推荐信的概率为0.632。

prob_I:
+------+----------+
| L    |   phi(L) |
+======+==========+
| L(0) |   0.3680 |
+------+----------+
| L(1) |   0.6320 |
+------+----------+

源码剖析

  • BayesianNetwork
    pgmpy中BayesianNetwork类继承于DAG类。DAG类是基于network的有向图模块构建的,该类返回一个有向无环图。一个简要的贝叶斯网络的伪代码如下:
class BayesianNetwork(DAG):
    def __init__(self, ebunch=None, latents=set()):
        """
        构造一个贝叶斯网络模型;
        模型存储节点以及带有条件概率表和其他属性的边;
        边为有向边;
        """
        super(BayesianNetwork, self).__init__(ebunch=ebunch, latents=latents)
        self.cpds = []
        self.cardinalities = defaultdict(int)

    def add_cpds(self, *cpds):
        """
        # 添加条件概率分布到贝叶斯网络中
        cpds  :  list, set, tuple (array-like), List of CPDs which will be associated with the model
        """
        for cpd in cpds:
            if not isinstance(cpd, (TabularCPD, ContinuousFactor)):
                raise ValueError("Only TabularCPD or ContinuousFactor can be added.")

            if set(cpd.scope()) - set(cpd.scope()).intersection(set(self.nodes())):
                raise ValueError("CPD defined on variable not in the model", cpd)

            for prev_cpd_index in range(len(self.cpds)):
                if self.cpds[prev_cpd_index].variable == cpd.variable:
                    logging.info(f"Replacing existing CPD for {cpd.variable}")
                    self.cpds[prev_cpd_index] = cpd
                    break
            else:
                self.cpds.append(cpd)

    def get_cardinality(self, node=None):
        """
        返回节点(随机变量)的取值个数
        """
        if node is not None:
            return self.get_cpds(node).cardinality[0]
        else:
            cardinalities = defaultdict(int)
            for cpd in self.cpds:
                cardinalities[cpd.variable] = cpd.cardinality[0]
            return cardinalities

构造一个贝叶斯网络示例:

from pgmpy.models import BayesianNetwork
from pgmpy.factors.discrete import TabularCPD
student = BayesianNetwork([('diff', 'grade'), ('intel', 'grade')]) # 节点指向关系 diff->grade,intel->grade
cpd_diff = TabularCPD('diff', 2, [[0.6], [0.4]])
cpd_intel = TabularCPD('intel', 2, [[0.7], [0.3]])
cpd_grade = TabularCPD('grade', 2, [[0.1, 0.9, 0.2, 0.7],
 [0.9, 0.1, 0.8, 0.3]],['intel', 'diff'], [2, 2])
student.add_cpds(cpd_diff,cpd_intel,cpd_grade)
student.get_cardinality() # defaultdict(int, {'diff': 2, 'intel': 2, 'grade': 2})
print(f"grade节点的取值个数:{student.get_cardinality('grade')}") # grade节点的取值个数:2

TabularCPD
TabularCPD类定义了各种条件概率分布表(conditional probability distribution table)。
简要代码如下:

构建一个条件概率表示例:

cpd = TabularCPD(variable='grade', # 随机变量名
                 variable_card=3, # 随机变量的取值个数
                 values=[[0.1,0.1,0.1,0.1,0.1,0.1], # 该随机变量的概率表
                        [0.1,0.1,0.1,0.1,0.1,0.1],
                        [0.8,0.8,0.8,0.8,0.8,0.8]],
                evidence=['diff', 'intel'], # 该随机变量的依赖变量
                 evidence_card=[2,3]) # 依赖变量的取值个数
print(cpd)

---------------------------------------------------------------------------------------------------------------------------------

参考资料
1.https://pgmpy.org/detailed_notebooks/2.%20Bayesian%20Networks.html
2.Brady Neal. 2020.Introduction to Causal Inference from a machine learning perspective[M], chapter 3, p28-30.
3.Conrady S , Jouffe L . Bayesian Networks & BayesiaLab - A Practical Introduction for Researchers[M]. 2015.
4.Pearl J . Causality: models, reasoning, and inference[M]. Cambridge University Press, 2000.
A Bayesian network approach for population synthesis. 5.https://www.sciencedirect.com/science/article/pii/S0968090X15003599


强烈推荐阅读贝叶斯网络的发明者朱迪亚·珀尔(Judea Pearl)的书

Causality: models, reasoning, and inference,了解更多细节。
 

python写的一段贝叶斯网络的程序 This file describes a Bayes Net Toolkit that we will refer to now as BNT. This version is 0.1. Let's consider this code an "alpha" version that contains some useful functionality, but is not complete, and is not a ready-to-use "application". The purpose of the toolkit is to facilitate creating experimental Bayes nets that analyze sequences of events. The toolkit provides code to help with the following: (a) creating Bayes nets. There are three classes of nodes defined, and to construct a Bayes net, you can write code that calls the constructors of these classes, and then you can create links among them. (b) displaying Bayes nets. There is code to create new windows and to draw Bayes nets in them. This includes drawing the nodes, the arcs, the labels, and various properties of nodes. (c) propagating a-posteriori probabilities. When one node's probability changes, the posterior probabilities of nodes downstream from it may need to change, too, depending on firing thresholds, etc. There is code in the toolkit to support that. (d) simulating events ("playing" event sequences) and having the Bayes net respond to them. This functionality is split over several files. Here are the files and the functionality that they represent. BayesNetNode.py: class definition for the basic node in a Bayes net. BayesUpdating.py: computing the a-posteriori probability of a node given the probabilities of its parents. InputNode.py: class definition for "input nodes". InputNode is a subclass of BayesNetNode. Input nodes have special features that allow them to recognize evidence items (using regular-expression pattern matching of the string descriptions of events). OutputNode.py: class definition for "output nodes". OutputBode is a subclass of BayesNetNode. An output node can have a list of actions to be performed when the node's posterior probability exceeds a threshold ReadWriteSigmaFiles.py: Functionality for loading and saving Bayes nets in an XML format. SampleNets.py: Some code that constructs a sample Bayes net. This is called when SIGMAEditor.py is started up. SIGMAEditor.py: A main program that can be turned into an experimental application by adding menus, more code, etc. It has some facilities already for loading event sequence files and playing them. sample-event-file.txt: A sequence of events that exemplifies the format for these events. gma-mona.igm: A sample Bayes net in the form of an XML file. The SIGMAEditor program can read this type of file. Here are some limitations of the toolkit as of 23 February 2009: 1. Users cannot yet edit Bayes nets directly in the SIGMAEditor. Code has to be written to create new Bayes nets, at this time. 2. If you select the File menu's option to load a new Bayes net file, you get a fixed example: gma-mona.igm. This should be changed in the future to bring up a file dialog box so that the user can select the file. 3. When you "run" an event sequence in the SIGMAEditor, the program will present each event to each input node and find out if the input node's filter matches the evidence. If it does match, that fact is printed to standard output, but nothing else is done. What should then happen is that the node's probability is updated according to its response method, and if the new probability exceeds the node's threshold, then its successor ("children") get their probabilities updated, too. 4. No animation of the Bayes net is performed when an event sequence is run. Ideally, the diagram would be updated dynamically to show the activity, especially when posterior probabilities of nodes change and thresholds are exceeded. To use the BNT, do three kinds of development: A. create your own Bayes net whose input nodes correspond to pieces of evidence that might be presented and that might be relevant to drawing inferences about what's going on in the situation or process that you are analyzing. You do this by writing Python code that calls constructors etc. See the example in SampleNets.py. B. create a sample event stream that represents a plausible sequence of events that your system should be able to analyze. Put this in a file in the same format as used in sample-event-sequence.txt. C. modify the code of BNT or add new modules as necessary to obtain the functionality you want in your system. This could include code to perform actions whenever an output node's threshold is exceeded. It could include code to generate events (rather than read them from a file). And it could include code to describe more clearly what is going on whenever a node's probability is updated (e.g., what the significance of the update is -- more certainty about something, an indication that the weight of evidence is becoming strong, etc.)
贝叶斯网络是一种用于建模概率关系的图模型。在Python中,可以使用pgmpy库来实现贝叶斯网络的构建和推理。首先,确保你的Python环境是3.7.X版本,其中X必须大于等于1,并安装了pgmpy所需的其他模块,包括networkX、scipy、numpy、pytorch、tqdm、pandas、pyparsing、statsmodels和joblib。\[1\] 在贝叶斯网络中,有一些重要的概念需要了解。其中,条件独立性是指在贝叶斯网络中,如果两个节点是直接连接的,它们肯定是非条件独立的,即存在直接因果关系。而局部马尔可夫性质是指在一个更一般的贝叶斯网络中,每个随机变量在给定其父节点的情况下,条件独立于它的非后代节点。\[2\] 举个例子,假设我们要构建一个诊断癌症的贝叶斯网络。我们有一些数据信息,比如美国有30%的人吸烟,每10万人中就有70人患有肺癌,每10万人中就有10人患有肺结核,每10万人中就有800人患有支气管炎,10%的人存在呼吸困难症状,大部分是由哮喘、支气管炎和其他非肺结核、非肺癌性疾病引起的。我们可以使用pgmpy库来构建这个贝叶斯网络,并填入相关参数。\[3\] 以下是一个基于pgmpy库构建贝叶斯网络的示例代码: ```python from pgmpy.models import BayesianModel cancer_model = BayesianModel(\[('Pollution', 'Cancer'), ('Smoker', 'Cancer'), ('Cancer', 'Xray'), ('Cancer', 'Dyspnoea')\]) ``` 在这个例子中,我们根据已知的结构和参数,使用BayesianModel构建了一个贝叶斯网络。网络的结构包括Pollution、Smoker、Cancer、Xray和Dyspnoea这些节点,它们之间的连接关系表示了它们之间的概率依赖关系。\[3\] 通过这个贝叶斯网络,我们可以进行各种推理和分析,例如计算给定某些证据条件下的概率分布。具体的实战应用可以根据具体的问题和数据进行进一步的开发和分析。 #### 引用[.reference_title] - *1* *2* *3* [【数据挖掘】贝叶斯网络理论及Python实现](https://blog.csdn.net/weixin_56516468/article/details/121419055)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值