Clojure DAG (Байесовская сеть)

Я хотел бы построить байесовскую сеть в clojure, так как я не нашел подобного проекта.

Я изучил много теории BN, но до сих пор не понимаю, как реализовать сеть (я не тот, кого люди называют «гуру» в чем-либо, но особенно в функциональном программировании).

Я знаю, что BN — это не что иное, как DAG и множество таблиц вероятностей (по одной для каждого узла), но теперь я не знаю, как реализовать DAG.

Моей первой идеей был огромный набор (DAG) с несколькими маленькими картами (узел DAG), каждая карта должна иметь имя (вероятно, ключ), таблицу вероятностей (еще одну карту?), вектор родителей и, наконец, вектор не-потомка.

Теперь я не знаю, как реализовать ссылку на родителей и не потомков (что я должен поместить в два вектора). Я предполагаю, что указатель должен быть идеальным, но его нет в clojure; Я мог бы поместить в вектор имя другого узла, но это будет медленно, не так ли?

Я думал, что вместо вектора я мог бы использовать больше набора, таким образом было бы быстрее найти потомков узла.

Аналогичная проблема для таблицы вероятностей, где мне все еще нужна ссылка на другие узлы.

Наконец, я также хотел бы изучить BN (построить сеть, начиная с данных), это означает, что я буду много изменять как таблицы вероятностей, ребро, так и узлы.

Должен ли я использовать изменяемые типы, или они только увеличат сложность?


person Siscia    schedule 14.07.2012    source источник
comment
Этот [SO вопрос][1] может вам помочь. [1]. com/questions/3127890/   -  person Ankur    schedule 14.07.2012
comment
У Часа Эмерик есть говорить о байесовских сетях, которые он дал ClojureConj. Там была некоторая полезная информация, которая может ответить на некоторые ваши вопросы.   -  person John Szakmeister    schedule 27.07.2012
comment
...сейчас на youtube.com/watch?v=xoSFcSqo1jQ   -  person Thumbnail    schedule 24.02.2014
comment
Вы видели ткацкий станок? github.com/aysylu/loom   -  person 象嘉道    schedule 22.06.2015
comment
Возможно, это не совсем связано, но вы заглядывали на robots.ox.ac.uk /~fwood/anglican (производное от Church в Clojure) см. также robots.ox.ac.uk/~fwood/anglican/examples/index.html?   -  person JoelKuiper    schedule 06.01.2016


Ответы (3)


Это не полный ответ, но вот возможная кодировка для примера сети из статьи в Википедии . Каждый узел имеет имя, список преемников (потомков) и таблицу вероятностей:

(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)))}))

Таблица вероятностей каждого узла задается как функция состояний родительских узлов и возвращает вероятность для значений true и false. Например,

((: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, чтобы извлечь соответствующую вероятность и умножить их.

Здесь я немного лукавлю, потому что полагаю, что функция соединения должна быть вычислена путем обхода графа (в общем случае может помочь макрос). Это также кажется немного запутанным, особенно в отношении состояний узлов, которые не обязательно бывают только истинными и ложными: в общем случае вы, скорее всего, будете использовать карту.

person coredump    schedule 17.07.2015

В общем, способ вычисления совместного распределения BN таков:

prod( P(node | parents of node) ) 

Для этого вам нужен список узлов, где каждый узел содержит

  • имя узла
  • список родителей
  • таблица вероятностей
  • список детей

таблицу вероятностей, возможно, проще всего обрабатывать, когда она плоская, где каждое значение строки соответствует родительской конфигурации, а каждый столбец соответствует значению для узла. Это предполагает, что вы используете запись для хранения всех значений. Значение узла также может содержаться внутри узла.

Узлы без родителей имеют только одну строку.

Каждая строка должна быть нормализована, после чего P(узел|родители) = таблица[строка,столбец]

На самом деле вам не нужен список дочерних элементов, но его наличие может упростить топологическую сортировку. DAG должна иметь возможность топологической сортировки.

Самая большая проблема возникает, поскольку количество ячеек в таблице вероятностей является произведением всех измерений родителей и себя. Я обработал это на С++, используя разреженную таблицу с использованием сопоставления строк.

Запрос к DAG — это другое дело, и лучший способ сделать это зависит от размера и достаточности приблизительного ответа. Здесь недостаточно места, чтобы прикрыть их. Поищите Murphy и набор инструментов Bayes Net Toolbox.

Я понимаю, что вы специально ищете реализацию, но, немного поработав, вы можете создать свою собственную.

person DAV    schedule 21.03.2016

Вы можете попытаться пойти еще дальше и иметь несколько карт, проиндексированных по идентификаторам узлов: одна карта для таблиц вероятностей, одна для родителей и одна для не-потомков (я не эксперт BN: что это, как это используется и т. д.? Это похоже на что-то, что можно пересчитать из родительской таблицы ^ W отношения ^ W карты).

person cgrand    schedule 14.02.2013