питонная реализация байесовских сетей для конкретного приложения - PullRequest
34 голосов
/ 24 сентября 2010

Вот почему я задаю этот вопрос: В прошлом году я написал код на C ++ для вычисления апостериорных вероятностей для модели определенного типа (описанной байесовской сетью). Модель работала довольно хорошо, и некоторые другие люди начали использовать мое программное обеспечение. Теперь я хочу улучшить свою модель. Поскольку я уже кодирую немного другие алгоритмы вывода для новой модели, я решил использовать python, потому что время выполнения не было критически важным, и python может позволить мне сделать более элегантный и управляемый код.

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

Я уже нашел отличный модуль python для сетевых графиков (networkx), который позволяет вам прикрепить словарь к каждому узлу и к каждому ребру. По сути, это позволило бы дать свойства узлов и ребер.

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

Например, в классической сети "Азия" (http://www.bayesserver.com/Resources/Images/AsiaNetwork.png), с известными состояниями "Результат XRay" и "Одышка") мне нужно написать функцию, чтобы вычислить вероятность того, что другие переменные имеют определенные значения (в зависимости от модели).

Вот мой вопрос программирования: Я собираюсь попробовать несколько моделей, и в будущем, возможно, я захочу попробовать другую модель после этого. Например, одна модель может выглядеть точно так же, как сеть в Азии. В другой модели направленное преимущество может быть добавлено от «Визита в Азию» до «Имеет рак легких». Другая модель может использовать исходный ориентированный граф, но вероятностная модель для узла «Одышка» с учетом узлов «Туберкулез или рак» и «Имеет бронхит» может отличаться. Все эти модели будут вычислять вероятность по-разному.

Все модели будут существенно перекрываться; например, множественные ребра, входящие в узел «ИЛИ», всегда будут иметь значение «0», если все входные данные равны «0» и «1» в противном случае. Но некоторые модели будут иметь узлы, которые принимают целочисленные значения в некотором диапазоне, в то время как другие будут логическими.

В прошлом я боролся с тем, как программировать подобные вещи. Я не собираюсь лгать; было скопировано и скопировано много кода, и иногда мне приходилось распространять изменения в одном методе на несколько файлов. На этот раз я действительно хочу потратить время, чтобы сделать это правильно.

Некоторые опции:

  1. Я уже делал это правильно. Сначала код, задавайте вопросы позже. Это быстрее, чтобы скопировать и вставить код и иметь один класс для каждой модели. Мир это темное и неорганизованное место ...
  2. Каждая модель - это свой собственный класс, но также подкласс общей модели BayesianNetwork. Эта общая модель будет использовать некоторые функции, которые будут переопределены. Страуструп был бы горд.
  3. Создайте несколько функций в одном классе, которые вычисляют разные вероятности.
  4. Кодируйте общую библиотеку BayesianNetwork и реализуйте мои проблемы вывода в виде конкретных графиков, считываемых этой библиотекой. Для узлов и ребер должны быть заданы свойства, такие как «Boolean» и «OrFunction», которые, с учетом известных состояний родительского узла, могут использоваться для вычисления вероятностей различных результатов. Эти строки свойств, такие как OrFunction, могут даже использоваться для поиска и вызова нужной функции. Возможно, через пару лет я сделаю что-то похожее на версию Mathematica 1988 года!

Большое спасибо за вашу помощь.

Обновление: Здесь очень помогают объектно-ориентированные идеи (у каждого узла есть назначенный набор узлов-предшественников определенного подтипа узла, и у каждого узла есть функция правдоподобия, которая вычисляет его вероятность различных конечных состояний с учетом состояний узлов-предшественников и т. Д.). ООП FTW!

Ответы [ 4 ]

22 голосов
/ 25 марта 2011

Я занимался такими вещами в свободное время довольно долго.Я думаю, что сейчас у меня третья или четвертая версия этой же проблемы.На самом деле я готовлюсь к выпуску еще одной версии Fathom (https://github.com/davidrichards/fathom/wiki) с включенными динамическими байесовскими моделями и другим уровнем персистентности.

Поскольку я пытался прояснить свой ответ, он стал довольно длинным.извиняюсь за это. Вот как я атаковал проблему, которая, кажется, отвечает на некоторые ваши вопросы (несколько косвенно):

Я начал с распада убеждений Иудеи Перл в Байесовской сети.это график с предыдущими коэффициентами (причинная поддержка), исходящими от родителей, и вероятностями (диагностическая поддержка), исходящими от детей. Таким образом, базовый класс - это просто BeliefNode, очень похожий на то, что вы описали с дополнительным узлом между BeliefNodes,LinkMatrix. Таким образом, я явно выбираю тип вероятности, который я использую, по типу LinkMatrix, который я использую. Это облегчает объяснение того, что сеть убеждений делает впоследствии, а также упрощает вычисления.

Любые подклассы или изменения, которые я внесу в базуc BeliefNode предназначен для связывания непрерывных переменных, а не для изменения правил распространения или ассоциаций узлов.

Я решил сохранить все данные внутри BeliefNode и только фиксированные данные в LinkedMatrix.Это связано с тем, что я поддерживаю чистые обновления убеждений при минимальной сетевой активности.Это означает, что мой BeliefNode хранит:

  • массив дочерних ссылок вместе с отфильтрованными вероятностями, приходящимися от каждого дочернего элемента, и матрицу ссылок, которая выполняет фильтрацию для этого дочернего элемента
  • anмассив родительских ссылок, а также отфильтрованные предыдущие шансы, исходящие от каждого родителя, и матрица ссылок, которая выполняет фильтрацию для этого родителя
  • объединенная вероятность узла
  • объединенные предыдущие коэффициентыузел
  • вычисленное убеждение или апостериорная вероятность
  • упорядоченный список атрибутов, которым все предшествующие шансы и вероятности придерживаются

LinkMatrix может быть создан с помощьюКоличество различных алгоритмов, в зависимости от характера отношений между узлами.Все модели, которые вы описываете, будут просто разными классами, которые вы будете использовать.Вероятно, проще всего сделать по умолчанию значение or-gate, а затем выбрать другие способы обработки LinkMatrix, если у нас есть особые отношения между узлами.

Я использую MongoDB для сохранения и кэширования.Я получаю доступ к этим данным внутри четной модели для скорости и асинхронного доступа.Это делает сеть достаточно производительной, а также имеет возможность быть очень большой, если это необходимо.Кроме того, поскольку я использую Mongo таким образом, я могу легко создать новый контекст для той же базы знаний.Так, например, если у меня есть диагностическое дерево, некоторая диагностическая поддержка для диагностики будет исходить от симптомов и тестов пациента.Что я делаю, так это создаю контекст для этого пациента, а затем распространяю свои убеждения, основываясь на доказательствах этого конкретного пациента.Аналогичным образом, если врач сказал, что пациент, вероятно, испытывает две или более болезней, то я мог бы изменить некоторые из моих матриц ссылок, чтобы по-разному распространять обновления убеждений.

Если вы не хотите использовать что-то вроде Mongoдля вашей системы, но вы планируете, чтобы над базой знаний работало более одного потребителя, вам нужно будет внедрить некую систему кэширования, чтобы постоянно работать с недавно обновленными узлами.

Моя работа с открытым исходным кодом, поэтому вы можете следить за ней, если хотите. Это все Ruby, поэтому он будет похож на ваш Python, но не обязательно будет заменой. Одна вещь, которая мне нравится в моем дизайне, это то, что вся информация, необходимая людям для интерпретации результатов, может быть найдена в самих узлах, а не в коде. Это можно сделать в качественных описаниях или в структуре сети.

Итак, вот некоторые важные отличия, которые у меня есть с вашим дизайном:

  • Я не вычисляю модель вероятности внутри класса, а скорее между узлами внутри матрицы ссылок. Таким образом, у меня нет проблемы объединения нескольких функций правдоподобия в одном классе. У меня также нет проблемы одной модели против другой, я могу просто использовать два разных контекста для одной и той же базы знаний и сравнивать результаты.
  • Я добавляю большую прозрачность, делая очевидными человеческие решения. То есть, если я решу использовать стандартный или-gate между двумя узлами, я знаю, когда я добавил это, и это было просто решение по умолчанию. Если я вернусь позже и изменю матрицу ссылок и пересчитаю базу знаний, у меня будет заметка о том, почему я это сделал, а не просто приложение, которое выбрало один метод вместо другого. Вы могли бы попросить своих потребителей делать заметки о подобных вещах. Тем не менее, если вы решите это, то, вероятно, будет хорошей идеей получить от аналитика пошаговый диалог о том, почему они настраивают все так или иначе.
  • Я могу быть более точным в отношении предыдущих шансов и вероятностей. Я точно не знаю, я просто видел, что вы использовали разные модели для изменения вероятностных чисел. Многое из того, что я говорю, может быть совершенно неактуально, если ваша модель вычисления апостериорных убеждений не сломается таким образом У меня есть преимущество в том, что я могу сделать три асинхронных шага, которые можно вызывать в любом порядке: передать измененные вероятности вверх по сети, передать измененные предыдущие шансы вниз по сети и пересчитать объединенное убеждение (апостериорную вероятность) самого узла .

Одно большое предостережение: кое-что из того, о чем я говорю, еще не выпущено. Я работал над вещами, о которых говорю, до двух часов утра, так что это определенно актуально и определенно привлекает мое внимание, но пока еще не все доступно для публики. Поскольку это моя страсть, я буду рад ответить на любые вопросы или поработать вместе над проектом, если хотите.

3 голосов
/ 25 марта 2011

Система логического вывода на основе ограничений Моцарта / Oz3 решает аналогичную проблему: вы описываете свою проблему в терминах ограничений на конечные доменные переменные, распространителей и распределителей ограничений, функций стоимости. Когда больше нет возможности сделать вывод, но есть все еще несвязанные переменные, он использует функции стоимости для разделения проблемного пространства на несвязанной переменной, что, скорее всего, сокращает затраты на поиск: то есть, если X находится между [a, c], такая переменная и c (a Вы, безусловно, можете реализовать схему копирования при записи в библиотеке на основе графов (подсказка: numpy использует различные стратегии, чтобы минимизировать копирование; если вы основываете на ней свое представление графа, вы можете получить семантику копирования при записи для бесплатно) и достичь своих целей.

2 голосов
/ 23 марта 2011

Я думаю, вам нужно задать пару вопросов, которые влияют на дизайн.

  1. Как часто вы будете добавлять модели?
  2. Ожидается ли от пользователей вашей библиотеки добавление новых моделей?
  3. Какой процент пользователей будет добавлять модели по сравнению с тем, какой процент будет использовать существующие?

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

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

Независимо от того, к какому конечному дизайну вы стремитесь, я бы начал с простого проекта реализации одного класса. Получите его, пройдя набор автоматических тестов, а затем сделайте рефакторинг в более полный дизайн. Также не забывайте контроль версий; -)

2 голосов
/ 23 марта 2011

Я не слишком знаком с Байесовскими сетями, поэтому я надеюсь, что следующее полезно:

В прошлом у меня была похожая проблема с регрессором Гауссова процесса вместо байесовский классификатор.

Я закончил тем, что использовал наследование, которое хорошо сработало. Все специфичные для модели параметры устанавливаются с помощью конструктора. Функции calc () являются виртуальными. Каскадирование различных методов (например, метод сумм, который объединяет произвольное число других методов) также хорошо работает таким образом.

...