如何使用pymc为贝叶斯网络创建条件概率表(CPTs)

3 投票
2 回答
4901 浏览
提问于 2025-04-18 00:59

我想建立一个贝叶斯网络,这个网络里有一些离散的变量(用pymc.Categorical表示),这些变量之间是有依赖关系的。
举个最简单的例子,假设有两个变量ab,它们都是分类变量,并且b依赖于a

下面是我用pymc尝试编写的代码(假设a可以取三个值,b可以取四个值)。我的想法是,CPT(条件概率表)的分布会通过数据来学习,使用pymc来实现。

import numpy as np
import pymc as pm
aRange = 3
bRange = 4

#make variable a
a = pm.Categorical('a',pm.Dirichlet('aCPT',np.ones(aRange)/aRange))

#make a CPT table as an array of 
CPTLines = np.empty(aRange, dtype=object)
for i in range(aRange):
    CPTLines[i] = pm.Dirichlet('CPTLine%i' %i,np.ones(bRange)/bRange)

#make a deterministic node that holds the relevant CPT line (dependent on state1)
@pm.deterministic
def selectedCPTLine(CPTLines=CPTLines,a=a):
    return CPTLines[a]

#make a node for variable b 
b=pm.Categorical('b', selectedCPTLine)

model = pm.MCMC([a, b, selectedCPTLine])

如果我们画出这个模型,它看起来像这样

但是,当我运行这段代码时,出现了一个错误:

Probabilities in categorical_like sum to [ 0.8603345]

显然,pymc可以将一个Dirichlet变量作为Categorical变量的参数。
当Categorical变量接收到Dirichlet变量作为参数时,它会知道需要一个k-1的概率向量,并假设第k个概率使得这个向量的总和为1。不过,当Dirichlet变量是一个确定性变量的输出时,这就出问题了,而我正需要这样来构建CPT。

我这样做对吗?如何解决表示不匹配的问题?我应该提到的是,我对pymc和Python还比较陌生。

这个问题与之前在使用pymc构建离散状态马尔可夫模型的问题有关。

2 个回答

0

有几个让人困惑的地方:

  • 你的模型似乎没有包含任何数据(观察到的随机性),所以没有信息可以用来调整模型。
  • 不太明白你说的“Dirichlet变量是确定性输出”是什么意思。只要概率的长度是k-1,并且它们的总和小于1,那就没问题。如果有一个值的总和是1,你可以只传递前k-1个值。
2

好的,谢谢。问题是,通常情况下,PyMC会把Dirichlet识别为Categorical的父级,并完成概率的简单形状(简单形状就是一种数学概念,表示概率的总和为1的情况)。但是在这里,你的Categorical被放在一个容器里,这样Categorical就没有自动进行必要的调整。下面的代码可以帮你解决这个问题:

import numpy as np
import pymc as pm
aRange = 3
bRange = 4

aCPT = pm.Dirichlet('aCPT', np.ones(aRange))

#make variable a
a = pm.Categorical('a', aCPT)

#make a CPT table as an array of
CPTLines = [pm.Dirichlet('CPTLine%i' %i, np.ones(bRange)) for i in range(aRange)]

#make a node for variable b
@pm.stochastic(dtype=int)
def b(value=0, CPT=CPTLines, a=a):
    return pm.categorical_like(value, p=pm.extend_dirichlet(CPT[a]))

model = pm.MCMC([a, b, CPTLines])

希望这能帮到你。

撰写回答