14

我想建立一個clojure貝葉斯網絡,因爲我還沒有找到任何類似的項目。我已經研究了很多BN的理論,但我仍然看不到如何實現網絡(我不是什麼人稱任何東西的「大師」,但特別是不能用於函數式編程)。Clojure DAG(貝葉斯網絡)

我知道一個BN不過是一個DAG和一個很多的概率表(每個節點一個),但現在我沒有粘合劑如何實現DAG。

我的第一個想法是一個巨大的集合(DAG)和一些小地圖(DAG的節點),每個地圖應該有一個名稱(可能是一個鍵)一個概率表(另一個地圖?)父母以及最後一個 -descendant的載體。

現在我不知道如何實現父母和非後代的參考(我應該把這兩個向量)。 我想指針應該是完美的,但clojure缺乏它;我可以將矢量名稱放在另一個節點的名稱中,但它會變慢,不是嗎?

我在想,代替矢量我可以使用更多的集合,這樣可以更快地找到節點的後代。

概率表的類似問題,我仍然需要其他節點的參考。

最後我也想學習BN(通過數據建立網絡)這意味着我將更改很多概率表,邊和節點。

我應該使用可變類型還是隻增加複雜性?

+0

這[SO問題] [1]可以幫助你。 [1]:http:// stackoverflow。com/questions/3127890/clojure-or-scheme-bayesian-classification-libraries/3128224#3128224 – Ankur 2012-07-14 12:39:04

+1

Chas Emerick有一個[關於貝葉斯網絡的討論](http://blip.tv/clojure/chas-emerick-modeling-the -world-probabilistically-using-bayesian-networks-in-clojure-5961126)他給了ClojureConj。它有一些有用的信息可以回答你的一些問題。 – jszakmeister 2012-07-27 08:38:23

+0

...現在https://www.youtube.com/watch?v=xoSFcSqo1jQ – Thumbnail 2014-02-24 11:01:14

回答

0

你可能會嘗試去更平坦,並有幾個地圖索引節點ids:一個概率表的地圖,一個父母和一個非後裔(我不是國陣專家:這是怎麼回事等等?感覺像是可以從父母表中重新計算的東西^ W關係^ W圖)。

1

這不是一個完整的答案,但這裏是從wikipedia article的示例網絡的可能編碼。每個節點都有一個名稱,繼承人(兒童)的列表和概率表:

(defn node [name children fn] 
    {:name name :children children :table fn}) 

而且,這裏是構建真/假的概率小助手功能:

;; builds a true/false probability map 
(defn tf [true-prob] #(if % true-prob (- 1.0 true-prob))) 

以上函數返回當給定true值(其值爲false值)時,返回事件X=true(對於我們編碼的X概率變量)的概率。因爲網絡是一個DAG,所以我們可以直接引用節點(就像你提到的指針一樣),而不必關心循環引用。我們只是建立在拓撲順序圖:

(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值的概率。例如,

((:table (:grass-wet dag)) :sprinkler true :rain false) 

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

所得關節功能結合根據此公式的概率:

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

一般情況下,來計算BN的聯合分佈的方法是

prod(P(node | parents of node)) 

爲了實現這一目標,需要節點列表,其中每個節點包含

  • 節點名稱
  • 父母名單
  • 概率表
  • 兒童列表

概率表可能最容易處理時,每行對應於父配置,每列對應於節點的值。這假定您正在使用記錄來保存所有值。節點的值也可以包含在節點中。

沒有父母的節點只有一行。

每行應其P(節點|父母)後,進行歸一化=表[行,列]

你並不真正需要的孩子的名單,但有可能使拓撲排序更容易。 DAG必須能夠進行拓撲排序。

最大的問題在於概率表中的單元格數量是父代和自身所有維度的乘積。我在C++中使用一個使用行映射的稀疏表來處理這個問題。

查詢DAG是另一回事,做這件事的最好方法取決於規模以及是否有足夠的答案。這裏沒有足夠的空間來覆蓋他們。搜索墨菲和貝葉斯網絡工具箱可能會有所幫助

我意識到你正在專門尋找一個實現,但只要一點工作,你就可以推出自己的。