本帖最后由 白冥 于 2025-1-28 16:55 编辑
目录
- 概述
- 依赖库
- 类与方法概述
- Cpd类的详细说明
- Bayesian_Network类的详细说明
- 示例代码
概述
本贴将介绍两种用于构建和操作贝叶斯网络的 Python 类: Cpd 和 Bayesian_Network 。这些类提供了构建贝叶斯网络所需的核心功能,允许定义变量、变量的条件概率表(CPD),以及设置变量间的依赖关系。
依赖库
该项目依赖以下几个 Python 库:
- collections.deque : 用于队列操作,特别是在实现图的拓扑排序时。
- math : 提供数学计算支持。
- typing : 用于类型注解。
类与方法概述
3.1 Cpd类
Cpd 类用于表示贝叶斯网络中每个节点的条件概率分布(CPD)。它通过指定变量及其父节点,定义了该变量在给定父节点条件下的概率值。
- class Cpd:
- def __init__(self, variable: str, variable_card: int, values: List[List[float]], parents: List[str] = [], parent_cards: List[int] = []):
- self.variable=variable
- self._variable_card = variable_card
- self.values=values
- self.parents=parents
- self._parent_cards = parent_cards
复制代码
关键属性:
- variable : 当前变量的名称(字符串类型)。
- variable_card : 当前变量的状态数(整数类型)。
- values : 条件概率表(二维列表,每行对应一种父节点状态的条件概率)。
- parents : 当前变量的父节点列表(字符串类型)。
- parent_cards : 父节点的状态数(整数类型列表)。
3.2 Bayesian_Network类
Bayesian_Network 类用于表示贝叶斯网络,提供了网络结构的定义、拓扑排序和条件概率分布的添加等功能。贝叶斯网络由节点(变量)和它们之间的有向边组成。
- class Bayesian_Network:
- def __init__(self,edges:List[Tuple[str,str]]):
- self._nodes=self._add_nodes(edges)
- self._parents=self._add_parents(edges, self._nodes)
- self._neighbors=self._add_neighbors(edges, self._nodes)
- if not self._is_acyclic_graph(edges, self._nodes, self._neighbors):
- raise ValueError("Bayesian network is DAG")
- self._cpds=dict()
- def _add_nodes(self, edges):
- nodes=set()
- for node0,node1 in edges:
- nodes.update([node0,node1])
- return list(nodes)
- def _add_parents(self, edges, nodes):
- parents = {node: set() for node in nodes}
- for node0, node1 in edges:
- parents[node1].add(node0)
- return parents
- def _add_neighbors(self, edges, nodes):
- neighbors = {node: set() for node in nodes}
- for node0, node1 in edges:
- neighbors[node0].add(node1)
- return neighbors
- def _is_acyclic_graph(self, edges, nodes, neighbors):
- in_degree = {node: 0 for node in nodes}
- for node0, node1 in edges:
- in_degree[node1] += 1
- queue = deque([node for node, degree in in_degree.items() if degree == 0])
- visited = set()
- while queue:
- node = queue.popleft()
- for neighbor in neighbors[node]:
- in_degree[neighbor] -= 1
- if in_degree[neighbor] == 0:
- queue.append(neighbor)
- visited.add(node)
- return len(visited)==len(in_degree)
- def add_cpds(self, *cpds: Cpd):
- for cpd in cpds:
- if cpd.variable not in self._nodes:
- raise ValueError(f"Variable {cpd.variable} is not a node in the model")
- for parent in cpd.parents:
- if parent not in self._parents[cpd.variable]:
- raise ValueError(f"Parent node {parent} is not connected to {cpd.variable} in the model")
- self._cpds[cpd.variable] = cpd
复制代码
关键方法:
- __init__(self, edges: List[Tuple[str, str]]) : 初始化贝叶斯网络,接受网络中的边(变量间的依赖关系)。
- _add_nodes(self, edges) : 从边列表中提取所有节点。
- _add_parents(self, edges, nodes) : 生成每个节点的父节点列表。
- _add_neighbors(self, edges, nodes) : 生成每个节点的邻居节点列表。
- _is_acyclic_graph(self, edges, nodes, neighbors) : 检查图是否为无环图(DAG)。
- add_cpds(self, *cpds: Cpd) : 向网络中添加条件概率分布(CPD)。
Cpd类的详细说明
4.1 __init__ 方法
和上面的一样,不说了
Bayesian_Network类的详细说明
5.1 __init__方法
edges : 由一组二元组(边)组成的列表,表示网络中节点之间的依赖关系。每个二元组表示一个有向边,其中第一个元素是父节点,第二个元素是子节点。
此方法用于初始化贝叶斯网络。通过提供网络中的边,它将自动添加所有节点、父节点和邻居节点。同时,方法会检查网络的拓扑是否是无环图(DAG),因为贝叶斯网络必须满足这一条件。如果图中存在环,则会抛出 ValueError 异常。
5.2 _add_nodes 方法
5.3 _add_parents 方法
5.4 _add_neighbors 方法
以上方法的逻辑都是一样的,相信大家光看代码就能清楚。都是遍历边,然后生成对应的数据结构。不再赘述。
5.5 _is_acyclic_graph 方法
edges : 由一组二元组(边)组成的列表,表示网络中节点之间的依赖关系。
nodes : 网络中所有节点的列表。
neighbors : 每个节点的邻居节点列表。
此方法用于检查网络中的图是否为有向无环图(DAG)。通过计算每个节点的入度并进行拓扑排序,验证图是否有环。如果存在环,方法将返回 False ;否则返回 True 。
5.6 add_cpds 方法
cpds : 一个或多个 Cpd 实例,表示添加到网络中的条件概率分布。
此方法用于将条件概率分布添加到贝叶斯网络中。它检查每个 Cpd 实例是否有效,即变量是否在网络中,并且父节点是否存在于网络的父节点列表中。如果 Cpd 实例无效,则抛出 ValueError 异常。
示例代码
- # 定义贝叶斯网络的边
- edges = [
- ('A', 'B'),
- ('A', 'C'),
- ('B', 'D'),
- ('C', 'D')
- ]
- # 创建贝叶斯网络实例
- bn = Bayesian_Network(edges)
- # 创建条件概率分布实例
- cpd_A = Cpd(variable='A', variable_card=2, values=[[0.1], [0.9]])
- cpd_B = Cpd(variable='B', variable_card=2, values=[[0.8, 0.2], [0.3, 0.7]], parents=['A'], parent_cards=[2])
- cpd_C = Cpd(variable='C', variable_card=2, values=[[0.7, 0.3], [0.4, 0.6]], parents=['A'], parent_cards=[2])
- cpd_D = Cpd(variable='D', variable_card=2, values=[[0.6, 0.4, 0.5, 0.5], [0.2, 0.8, 0.3, 0.7]], parents=['B', 'C'], parent_cards=[2, 2])
- # 将条件概率分布添加到贝叶斯网络中
- bn.add_cpds(cpd_A, cpd_B, cpd_C, cpd_D)
复制代码

补充-2025-01-27 修改次数4
贝叶斯网络,是一种概率图模型,它通过DAG表示一组随机变量及其条件依赖关系。当我们想要表示一组随机变量的因果关系时,最常使用贝叶斯网络。
贝叶斯网络的局部独立性:对于贝叶斯网络内的任何随机变量X,若它的父级变量是Pa(X),那么X与自身的除父级节点外的任何非后代变量Non-Desc(X),都与X条件独立:记作X⊥Non-Desc(X) | Pa(X)。
贝叶斯网络的基本结构:
链式结构A→B→C
V型结构A→B←C
倒V型结构A←B→C
贝叶斯网络的全局独立性:对于贝叶斯网络内的任意随机变量X,若对于任意不是X且不与X相邻的的随机变量Y,若X,Y之间任意路径path都存在阻断点W,则X,Y条件独立。这称为贝叶斯网络的全局独立性,记为X⊥Y | W。
阻断点:
对于路径path上的任意链式结构…A→B→C…,若随机变量B是给定的,则B是路径path上的阻断点;
对于路径path上的任意V型结构…A→B←C…,若随机变量B是不定的,则B是路径path上的阻断点;
对于路径path上的任意倒V型结构…A←B→C…,若随机变量B是给定的,则B是路径path上的阻断点。
补充-2025-01-28 修改次数5
独立性能做一个事情,那就是化简概率表达式。事实上,任何一个贝叶斯网络,都可以唯一表示一个分布,那就是全体随机变量的联合分布。
对于一个有N个随机变量的贝叶斯网络,它代表全体随机变量的联合分布,根据概率链式法则我们知道,P(X₁,X₂,X₃,…,Xɴ) = P(X₁|X₂,X₃,…,Xɴ) × P(X₂|X₃,X₄,…,Xɴ) × P(X₃|X₄,X₅,…,Xɴ) × … × P(Xɴ|Xɴ₋₁) × P(Xɴ)。
对于我们所举的例子,就以这张图为例。
(节点,箭头代表依赖关系)
假设一个贝叶斯网络的节点和边构成的DAG如图所示,它代表的联合概率分布为P(A,B,C,D,E,F,G) = P(A|B,C,D,E,F,G) × P(B|C,D,E,F,G) × P(C|D,E,F,G) × P(D|E,F,G) × P(E|F,G) × P(F|G) × P(G)
让我们分析每个点的独立性。
-------------
由局部独立性可得:
A的父级变量是B,C,则A⊥D,E,F,G | B,C
B的父级变量是D,则B⊥C,E,F,G | D
C的父级变量是D,F,G,则C⊥B,E | D,F,G
D的父级变量是E,则D⊥F,G | E
E,F,G没有父级变量
------------
由全局独立性可得:
(A,B,C,D由于可能独立的点都找完了,剩下来的都是父级节点或后代节点,是绝对相关的,因此不分析)
E到F有两条路径:
E→D→C←F,C是阻断点
E→D→B→A←C←F,A是阻断点
因此E⊥F | A,C
E到G有两条路径:
E→D→C←G,C是阻断点
E→D→B→A←C←G,A是阻断点
因此E⊥G | A,C
F到G有一条路径:
F→C←G,C是阻断点
因此F⊥G | C
------------
由随机变量独立的性质,P(A,B,C,D,E,F,G)可化简为 P(A,B,C,D,E,F,G) = P(A|B,C) × P(B|D) × P(C|D,F,G) × P(D|E) × P(E) × P(F) × P(G)。
此时此刻你会发现,贝叶斯网络全体随机变量的联合分布就是贝叶斯网络的全体随机变量的cpd(条件概率分布)的乘积,即P(X₁,X₂,X₃,…,Xɴ) = ΠP(Xᵢ | Pa(Xᵢ)) (i = 1 → N)。
补充-2025-01-28 修改次数2
所谓边际化就是把联合分布中若干随机变量分离出来考虑,消除对需求无关的变量。边际化最简单的方式就是变量消除。
假如我们只想知道P(A,B,C),我们就需要消除D,E,F,G的影响。
我们知道了P(A,B,C,D,E,F,G) = P(A|B,C) × P(B|D) × P(C|D,F,G) × P(D|E) × P(E) × P(F) × P(G)。
根据全概率公式,我们有P(A,B,C) = P(A|B,C) × Σᴅ(P(B|D) × ΣғΣɢ(P(C|D,F,G) × Σᴇ(P(D|E) × P(E) × P(F) × P(G))))。
事实上,我们边际化对任何随机变量的联合分布都有效,最终能得到若干随机变量的联合分布或单一随机变量的边际分布。
|