手动和使用 pgmpy(贝叶斯图形模型)计算条件概率之间的不一致

机器算法验证 条件概率 图形模型 贝叶斯网络
2022-03-22 19:18:36

我正在自学贝叶斯图形网络。我正在尝试使用 python 包pgmpy在 python 中生成网络。这似乎是一个很好的资源。

对于我的第一个测试,我生成了一个如下所示的简单网络(我设置了已知概率和条件概率来推断无条件概率): 在此处输入图像描述

现在,我将的概率以及的概率输入到 pgmpy 中的贝叶斯图形模型结构中:ABP(C|A,B)

IN:
#These are based on the the Monte Hall example found at https://github.com/pgmpy/pgmpy/blob/dev/examples/Monte%20Hall%20Problem.ipynb

from pgmpy.models import BayesianModel
from pgmpy.factors import TabularCPD

# Defining the network structure
model = BayesianModel([('A', 'C'), ('B', 'C')])

# Defining the CPDs:
cpd_p = TabularCPD('A', 2, [[0.99, 0.01]])
cpd_a = TabularCPD('B', 2, [[0.9, 0.1]])
cpd_t = TabularCPD('C', 2, [[0.9, 0.5, 0.4, 0.1], 
                                  [0.1, 0.5, 0.6, 0.9]],
                  evidence=['A', 'B'], evidence_card=[2, 2])

# Associating the CPDs with the network structure.
model.add_cpds(cpd_p, cpd_a, cpd_t)

# Some other methods
model.get_cpds()


OUT:
[<TabularCPD representing P(A:2) at 0x10e24cfd0>,
 <TabularCPD representing P(B:2) at 0x10e24cf10>,
 <TabularCPD representing P(C:2 | A:2, B:2) at 0x10df9a750>]

但是,当我计算 pgmpy 中的概率时,我得到:

IN:
# Infering the posterior probability 
from pgmpy.inference import VariableElimination

print 'P(B|A=1,C=1)'
infer = VariableElimination(model)
posterior_p = infer.query(['B'], evidence={'A': 1, 'C': 1})
print(posterior_p['B'])

print 'P(B|C=1)'
posterior_p = infer.query(['B'], evidence={'C': 1})
print(posterior_p['B'])

print 'probs'
posterior_p = infer.query(['B','C','A'])
for entry in posterior_p:
    print posterior_p[entry]


OUT:
P(B|A=1,C=1)
+-----+----------+
| B   |   phi(B) |
|-----+----------|
| B_0 |   0.8333 |
| B_1 |   0.1667 |
+-----+----------+
P(B|C=1)
+-----+----------+
| B   |   phi(B) |
|-----+----------|
| B_0 |   0.6082 |
| B_1 |   0.3918 |
+-----+----------+
probs
+-----+----------+
| A   |   phi(A) |
|-----+----------|
| A_0 |   0.9900 |
| A_1 |   0.0100 |
+-----+----------+
+-----+----------+
| C   |   phi(C) |
|-----+----------|
| C_0 |   0.8461 |
| C_1 |   0.1539 |
+-----+----------+
+-----+----------+
| B   |   phi(B) |
|-----+----------|
| B_0 |   0.9000 |
| B_1 |   0.1000 |
+-----+----------+

但是,当我手动计算上面显示的条件概率(或变量的总概率)时(从无条件概率计算),我得到不同的答案:C

P(B=1|A=1,C=1)=P(B=1|A=1,C=1)P(B=0|A=1,C=1)+P(B=1|A=1,C=1)=0.00090.0054+0.0009=0.143

P(B=1|C=1)=P(B=1,C=1)P(C=1)=0.0495+0.00090.0891+0.0495+0.0054+0.0009=0.348

P(C=1)=0.0891+0.0495+0.0054+0.0009=0.145

显然这与 pgmpy 输出的概率不同。

有人知道我哪里出错了吗?使用我的“手动”计算或编码。

谢谢!!!

3个回答

似乎以为我想通了。我在这里发布它以防万一它对某人有帮助。

好吧,事实证明我的“手动”计算并没有出错,但这确实是 pgmpy 包的问题。出于某种原因,它在给定之间的独立性(它们应该在不知道 C 的情况下是独立的)。ABC

我将软件包更新为开发人员版本,它给出了预期的结果。

我尝试安装新软件包,但错误仍然存​​在。所以我查看了贝叶斯网络代码本身并发现了错误。

查找后代时,它在 BayesianModel.py 的第 530 行。因为neighbors是一个迭代器,在visit.extend之后它是空的,所以descendants.extend什么也不做,结果是空的。我通过将邻居作为列表来修复它。

    Since Bayesian Networks are acyclic, this is a very simple dfs
    which does not remember which nodes it has visited.
    """
    descendents = []
    visit = [node]
    while visit:
        n = visit.pop()
        neighbors = self.neighbors(n)
        visit.extend(neighbors)
        **descendents.extend(neighbors)**
    return descendents

确认这在 0.1.14 版本中运行良好(与手动计算匹配)。注意我必须对代码进行更改,以修复 pgmpy 的使用方式(不正确的形状)和 Python 3 的错误。这是更新的代码。

from pgmpy.models import BayesianModel
from pgmpy.factors.discrete import TabularCPD

# Defining the network structure
model = BayesianModel([('A', 'C'), ('B', 'C')])

# Defining the CPDs:
cpd_p = TabularCPD('A', 2, [[0.99], [0.01]])
cpd_a = TabularCPD('B', 2, [[0.9], [0.1]])
cpd_t = TabularCPD('C', 2, [[0.9, 0.5, 0.4, 0.1],
                            [0.1, 0.5, 0.6, 0.9]],
                  evidence=['A', 'B'], evidence_card=[2, 2])

# Associating the CPDs with the network structure.
model.add_cpds(cpd_p, cpd_a, cpd_t)

# Some other methods
model.get_cpds()

from pgmpy.inference import VariableElimination

print('P(B|A=1,C=1)')
infer = VariableElimination(model)
posterior_p = infer.query(['B'], evidence={'A': 1, 'C': 1})
print(posterior_p)

print('P(B|C=1)')
posterior_p = infer.query(['B'], evidence={'C': 1})
print(posterior_p)

print('probs')
posterior_p = infer.query(['B','C','A'])
print(posterior_p)