python - 贝叶斯网络针对特定应用的pythonic实现

标签 python bayesian bayesian-networks

这就是为什么我问这个问题:
去年,我编写了一些C++代码来计算特定类型模型(由贝叶斯网络描述)的后验概率。该模型运行良好,其他人开始使用我的软件。现在,我想改进我的模型。由于我已经为新模型编写了略有不同的推理算法,因此我决定使用python,因为运行时并不是至关重要的,并且python可以让我编写更加优雅和易于管理的代码。

通常在这种情况下,我会在python中搜索现有的贝叶斯网络包,但是我使用的推理算法是我自己的,并且我还认为这将是一个很好的机会,以了解更多关于python良好设计的知识。

我已经找到了一个很棒的用于网络图的python模块(networkx),它允许您将字典附加到每个节点和每个边缘。本质上,这将使我可以指定节点和边的属性。

对于特定的网络及其观察到的数据,我需要编写一个函数来计算模型中未分配变量的可能性。

例如,在经典的“亚洲”网络(http://www.bayesserver.com/Resources/Images/AsiaNetwork.png)中,已知“XRay结果”和“呼吸困难”的状态,我需要编写一个函数来计算其他变量具有特定值的可能性(根据某些模型) )。

这是我的编程问题:
我将尝试一些模型,将来有可能在此之后再尝试其他模型。例如,一种模型可能看起来完全像亚洲网络。在另一种模型中,可以将“从亚洲访问”添加到“有肺癌”。另一个模型可能使用原始的有向图,但是给定“肺结核或癌症”和“有支气管炎”节点的“呼吸困难”节点的概率模型可能有所不同。所有这些模型将以不同的方式计算可能性。

所有模型将有大量重叠;例如,如果所有输入均为“0”,则进入“或”节点的多个边将始终为“0”,否则为“1”。但是某些模型的节点将采用某个范围内的整数值,而其他模型将为 bool 值。

过去,我一直在努力编写此类程序。我不会撒谎;有大量的复制和粘贴代码,有时我需要将单个方法中的更改传播到多个文件。这次我真的很想花时间做正确的事情。

一些选项:

  • 我已经以正确的方式进行了操作。首先编写代码,稍后再提问。复制和粘贴代码并为每个模型拥有一个类的速度更快。世界是一个黑暗而困惑的世界。
  • 每个模型都是其自己的类,也是常规BayesianNetwork模型的子类。这个通用模型将使用一些将被覆盖的功能。 Stroustrup将为此感到自豪。
  • 在同一类中创建多个函数以计算不同的可能性。
  • 编码一个通用的BayesianNetwork库,并将我的推理问题实现为该库读取的特定图形。节点和边缘应具有“ bool ”和“OrFunction”之类的属性,给定父节点的已知状态,这些属性可用于计算不同结果的概率。这些属性字符串(例如“OrFunction”)甚至可以用于查找和调用正确的函数。也许几年后,我会做出类似于1988年版本的Mathematica的东西!

  • 非常感谢你的帮助。

    更新:
    面向对象的思想在这里有很大帮助(每个节点都有一组指定的特定子类型的前任节点,每个节点都有一个似然函数,可以根据给定前任节点的状态计算其不同结果状态的可能性,等等)。 OOP FTW!

    最佳答案

    业余时间我一直在从事这类工作。我想我现在正在处理同一问题的第三版或第四版。我实际上正准备发布另一个版本的Fathom(https://github.com/davidrichards/fathom/wiki),其中包含动态贝叶斯模型和不同的持久层。

    当我试图弄清楚我的答案时,它已经相当长了。我对此表示歉意。这是我一直在解决问题的方式,它似乎回答了您的某些问题(某种程度上是间接的):

    我从Judea Pearl在贝叶斯网络中对信念传播的分解开始。也就是说,它是一个图表,其中 parent 有先验几率(因果支持),而 child 有几率(诊断支持)。这样,基本类就是BeliefNode,就像您在BeliefNodes之间的一个额外节点LinkMatrix所描述的那样。通过这种方式,我通过我使用的LinkMatrix类型显式选择了我正在使用的可能性类型。它使解释信念网络之后的工作变得更容易,并使计算更简单。

    我对基本BeliefNode所做的任何子类化或更改都将用于对连续变量进行装箱,而不是更改传播规则或节点关联。

    我决定将所有数据保留在BeliefNode中,而仅将固定数据保留在LinkedMatrix中。这与确保我以最少的网络 Activity 维护干净的信念更新有关。这意味着我的BeliefNode存储:

  • 子项引用数组,以及来自每个子项的已过滤似然性以及对该子项进行过滤的链接矩阵
  • 父级引用数组,以及来自每个父级的已过滤优先级优势以及为该父级
  • 进行过滤的链接矩阵
  • 节点
  • 的组合似然
  • 节点
  • 的组合先验赔率
  • 计算的置信度或后验概率
  • 所有先前优势和可能性都遵循
  • 的属性的有序列表

    根据节点之间关系的性质,可以使用多种不同的算法来构造LinkMatrix。您要描述的所有模型都只是您要使用的不同类。可能最简单的方法是默认为or-gate,然后如果节点之间有特殊关​​系,则选择其他方法来处理LinkMatrix。

    我使用MongoDB进行持久性和缓存。我在事件模型中访问此数据,以实现速度和异步访问。这使网络性能相当好,同时如果需要的话还可以有很大的机会。另外,由于我以这种方式使用Mongo,因此我可以轻松地为相同的知识库创建新的上下文。因此,例如,如果我有诊断树,则对诊断的某些诊断支持将来自患者的症状和检查。我要做的是为该患者创建上下文,然后根据该特定患者的证据来传播我的信念。同样,如果医生说患者可能患有两种或更多种疾病,那么我可以更改一些链接矩阵,以不同方式传播信念更新。

    如果您不想在系统上使用像Mongo这样的东西,但是您计划在知识库上使用多个消费者,则需要采用某种缓存系统以确保您正在使用新的缓存。 -随时更新节点。

    我的作品是开源的,因此您可以根据需要进行后续操作。都是Ruby,因此它与Python类似,但不一定是直接替代。我喜欢设计的一件事是,人类解释结果所需的所有信息都可以在节点本身中找到,而不是在代码中找到。这可以在定性描述中或在网络结构中完成。

    因此,这是我与您的设计之间的一些重要差异:
  • 我不在类内部而不是在链接矩阵内部的节点之间计算似然模型。这样,我就不会在同一个类中合并多个似然函数的问题。我也没有一个模型与另一个模型的问题,我可以将两个不同的上下文用于相同的知识库并比较结果。
  • 我通过使人为决策变得更加透明。也就是说,如果我决定在两个节点之间使用默认的或门,我知道何时添加它,这只是默认的决定。如果稍后再返回并更改链接矩阵并重新计算知识库,那么我会记下我为什么这样做,而不仅仅是选择了一种方法的应用程序。您可以让您的消费者记下这种事情。无论您解决了什么,从分析师那里获得关于他们为何以一种方式在另一种方式上进行设置的逐步对话可能是一个好主意。
  • 我可能会更明确地了解先前的几率和可能性。我不确定,我只是看到您正在使用不同的模型来更改您的可能性数字。如果您的计算后验信念的模型没有按照这种方式分解,那么我所说的大部分内容可能完全不相关。我的好处是能够执行三个异步步骤,这些步骤可以按任意顺序调用:将变化的可能性传递到网络上方,将变化的先验概率传递到网络下方,并重新计算节点本身的组合置信度(后验概率) 。

  • 一个重要的警告:我正在谈论的一些内容尚未发布。我一直在讨论直到今天凌晨2:00左右的内容,所以它绝对是最新的,而且也得到了我的定期关注,但尚未公开。由于这是我的一种热情,如果您愿意,我很乐意回答任何问题或在项目上共同努力。

    关于python - 贝叶斯网络针对特定应用的pythonic实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3783708/

    相关文章:

    r - 在 Stan 中是否不可能将矩阵/向量乘以标量值?

    python - 如何在 PyMC3 中定义一个模型,其中一个参数在多个条件下限制为相同值

    machine-learning - Scikits NB 与 NLTK NB 的性能对比

    python - conda 安全错误 : file has an incorrect size

    python - 在seaborn上绘制y轴网格和kdeplot之间的交集

    python - 如何更改 seaborn violinplot 图例标签?

    artificial-intelligence - 设计贝叶斯网络

    python - 无法使用 Mixin 类扩展 python IntEnum

    R:理解 MCMCglmm 的输出

    r - bnlearn + Rgraphviz : double arrows instead of undirected edges when customizing plots