首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >贝叶斯网络

贝叶斯网络
EN

Stack Overflow用户
提问于 2012-07-14 09:11:02
回答 3查看 1.4K关注 0票数 14

我想构建一个贝叶斯网络在clojure,因为我还没有发现任何类似的项目。

我已经学习了很多BN的理论,但我仍然不知道如何实现网络(我不是人们所说的“专家”,尤其是函数式编程)。

我知道BN不过是一个DAG和很多概率表(每个节点一个),但是现在我没有胶水来实现DAG。

我的第一个想法是一个巨大的集合( DAG)和一些小地图(DAG的节点),每个映射应该有一个名称(可能是a: key),一个概率表(另一张地图?)父母的向量最后是non-descendant.的向量

现在我不知道如何实现父母和非后代的参考(我应该把什么放在两个向量中)。我想指针应该是完美的,但是clojure缺少它;我可以在向量中插入另一个节点的名称,但是它会很慢,不是吗?

我在想,我可以用更多的集合来代替向量,这样就能更快地找到节点的后代。

类似的问题,对于概率表,我仍然需要在其他节点的一些参考。

最后,我还想学习BN (从数据开始构建网络),这意味着我将更改很多,包括概率表、边缘和节点。

我应该使用可变类型,还是它们只会增加复杂性?

EN

回答 3

Stack Overflow用户

发布于 2015-07-17 14:27:22

这不是一个完整的答案,但下面是来自维基百科文章的示例网络的可能编码。每个节点都有一个名称、一个继承者列表(子节点)和一个概率表:

代码语言:javascript
复制
(defn node [name children fn]
  {:name name :children children :table fn})

此外,下面是用于构建真/假概率的小助手函数:

代码语言:javascript
复制
;; builds a true/false probability map
(defn tf [true-prob] #(if % true-prob (- 1.0 true-prob)))

上面的函数返回一个闭包,当给定一个true值时,这个闭包(resp )。false值),返回事件X=true的概率(对于我们正在编码的X概率变量)。

由于网络是一个DAG,所以我们可以直接引用节点(与您提到的指针完全一样),而不必关心循环引用。我们只是按拓扑顺序构建图:

代码语言:javascript
复制
(let [gw (node "grass wet" [] (fn [& {:keys [sprinkler rain]}]
                            (tf (cond (and sprinkler rain) 0.99
                                      sprinkler 0.9
                                      rain 0.8
                                      :else 0.0))))

  sk (node "sprinkler" [gw]
           (fn [& {:keys [rain]}] (tf (if rain 0.01 0.4))))

  rn (node "rain" [sk gw]
           (constantly (tf 0.2)))]

  (def dag {:nodes {:grass-wet gw :sprinkler sk :rain rn}
        :joint (fn [g s r]
                 (*
                  (((:table gw) :sprinkler s :rain r) g)
                  (((:table sk) :rain r) s)
                  (((:table rn)) r)))}))

每个节点的概率表作为父节点状态的函数给出,并返回truefalse值的概率。例如,

代码语言:javascript
复制
((:table (:grass-wet dag)) :sprinkler true :rain false)

..。返回{:true 0.9, :false 0.09999999999999998}

由此产生的联合函数根据这个公式组合概率:

代码语言:javascript
复制
P(G,S,R) = P(G|S,R).P(S|R).P(R)

((:joint dag) true true true)返回0.0019800000000000004。实际上,((:table <x>) <args>)返回的每个值都是一个if的闭包,它返回知道概率变量状态的概率。我们用相应的true/false值调用每个闭包来提取适当的概率,并将它们相乘。

在这里,我有点作弊,因为我认为应该通过遍历图来计算联合函数(一般情况下,宏可能会有所帮助)。这也让人感到有点混乱,尤其是节点的状态,这并不一定是正确和错误的:在一般情况下,您很可能会使用映射。

票数 1
EN

Stack Overflow用户

发布于 2016-03-21 23:55:11

通常,计算BN的联合分布的方法是

代码语言:javascript
复制
prod( P(node | parents of node) ) 

要实现这一点,您需要一个节点列表,其中每个节点包含

  • 节点名
  • 父母名单
  • 概率表
  • 儿童名单

概率表在平的情况下可能最容易处理,每一行值对应于父配置,每列对应节点的值。这假设您使用一个记录来保存所有的值。节点的值也可以包含在节点中。

没有父节点的节点只有一行。

每一行都应标准化,在此之后,P(节点\父级)= tablerow,col

你并不真正需要孩子的列表,但是拥有它可以使拓扑排序变得更容易。DAG必须能够进行拓扑排序。

最大的问题是概率表中的细胞数是父母和自我的所有维度的乘积。我在C++中使用一个使用行映射的稀疏表来处理这个问题。

查询DAG是另一回事,最好的方法取决于大小和大致答案是否足够。这里没有足够的空间盖住他们。搜索Murphy和Bayes网络工具箱可能会有帮助

我意识到您正在专门寻找一个实现,但是,只要做一点点工作,您就可以自己滚动。

票数 1
EN

Stack Overflow用户

发布于 2013-02-14 09:53:45

您可能会尝试使用更多的方法,并通过节点it建立几个映射的索引:一个映射用于概率表,一个用于父母,另一个用于非后代(我不是BN专家:这是什么,它是如何使用的等等?)它感觉像是可以从父表^W关系^W映射重新计算的东西)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11482474

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档