34 votes

implémentation pythonique de réseaux bayésiens pour une application spécifique

C'est pourquoi je vous pose cette question: L'année dernière j'ai fait un peu de code C++ pour calculer les probabilités a posteriori pour un type particulier de modèle (décrit par un réseau Bayésien). Le modèle a fonctionné assez bien et quelques autres personnes ont commencé à utiliser mon logiciel. Maintenant, je veux améliorer mon modèle. Depuis que je suis déjà codage légèrement différents algorithmes d'inférence pour le nouveau modèle, j'ai décidé d'utiliser python en raison d'exécution n'était pas très important et python peuvent permettez-moi de rendre plus élégant et maniable code.

Généralement dans cette situation, je voudrais rechercher un réseau Bayésien package python, mais les algorithmes d'inférence que j'utilise sont les miennes, et j'ai aussi pensé que ce serait une excellente occasion d'en apprendre plus sur la bonne conception de python.

J'ai déjà trouvé un grand module python pour le réseau des graphes (networkx), qui permet d'attacher un dictionnaire à chaque nœud et chaque bord. Essentiellement, cela permettez-moi de vous donner des nœuds et des arêtes de propriétés.

Pour un réseau particulier et les données observées, j'ai besoin d'écrire une fonction qui calcule la probabilité de la non affecté de variables dans le modèle.

Par exemple, dans le classique "Asie" (réseauhttp://www.bayesserver.com/Resources/Images/AsiaNetwork.png), avec les états de "XRay Résultat" et "Dyspnée" connu, j'ai besoin d'écrire une fonction pour calculer la probabilité que les autres variables ont certaines valeurs (selon un certain modèle).

Voici ma programmation de la question: Je vais essayer de faire une poignée de modèles, et dans l'avenir, il est possible que je souhaite essayer un autre modèle par la suite. Par exemple, un modèle peut ressembler exactement le réseau Asie. Dans un autre modèle, un dirigé bord peut être ajouté à partir de "Visite à l'Asie" à "A un Cancer du Poumon." Un autre modèle pourrait utiliser l'original graphe orienté, mais le modèle de probabilité pour la "Dyspnée" nœud donné le "la Tuberculose ou le Cancer" et "Bronchite" nœuds peuvent être différentes. L'ensemble de ces modèles permettra de calculer la probabilité d'une façon différente.

Tous les modèles ont un chevauchement important; par exemple, plusieurs bords d'entrer dans un "Ou" nœud fera toujours un "0" si toutes les entrées sont à "0" et "1" dans le cas contraire. Mais certains modèles ont des nœuds qui prennent des valeurs entières dans une certaine gamme, tandis que d'autres devront être de type boolean.

Dans le passé, j'ai eu du mal avec la façon de programmer ce genre de choses. Je ne vais pas mentir; il y a eu une bonne quantité de copié et collé le code et j'ai parfois nécessaire pour propager les changements dans une méthode unique pour plusieurs fichiers. Cette fois, j'ai vraiment envie de passer du temps à faire de la bonne façon.

Quelques options:

  1. Je faisais déjà ce la bonne manière. Le premier Code, de poser des questions plus tard. Il est plus rapide de copier et de coller le code et d'avoir une classe pour chaque modèle. Le monde est un endroit sombre et la désorganisation de la place...
  2. Chaque modèle est sa propre classe, mais également une sous-classe d'un général BayesianNetwork modèle. Ce modèle général allons utiliser quelques fonctions qui vont être remplacées. Stroustrup serait fier.
  3. Faire plusieurs fonctions dans la même classe que le calcul des différentes probabilités.
  4. Code général BayesianNetwork de la bibliothèque et de mettre en œuvre mes inférence problèmes spécifiques des graphiques lue par cette bibliothèque. Les nœuds et les arêtes doivent être donné des propriétés comme "Booléen" et "OrFunction" qui, étant donné états connus du nœud parent, peut être utilisé pour calculer les probabilités des différents résultats. Ces chaînes de propriété, comme "OrFunction" pourrait même être utilisé pour rechercher et appeler la bonne fonction. Peut-être que dans quelques années je vais faire quelque chose de similaire à la version de 1988 de Mathematica!

Merci beaucoup pour votre aide.

Mise à jour: Orientée objet idées d'une grande aide ici (chaque nœud possède un ensemble de prédécesseur nœuds d'un certain nœud sous-type, et chaque nœud a une probabilité fonction qui calcule la probabilité d'occurrence des différents états des résultats étant donné les états de l'prédécesseur nœuds, etc.). LA PROGRAMMATION ORIENTÉE OBJET FTW!

22voto

David Richards Points 805

J'ai travaillé sur ce genre de chose dans mon temps libre pendant un certain temps. Je pense que j'en suis à ma troisième ou quatrième version de ce même problème dès maintenant. En fait, je suis prêt à sortir une nouvelle version de Fathom (https://github.com/davidrichards/fathom/wiki) avec bayésien dynamique des modèles inclus et une autre couche de persistance.

Comme j'ai essayé de faire ma réponse clair, il est devenu assez longue. Je m'en excuse. Voici comment j'ai été d'attaquer le problème, qui semble répondre à certaines de vos questions (un peu indirectement):

J'ai commencé par Judea Pearl répartition de la croyance de la propagation dans un Réseau Bayésien. C'est en fait un graphique avec avant de cotes (de cause à effet de soutien) en provenance des parents et des probabilités (diagnostiques) en provenance des enfants. De cette façon, la classe de base est juste un BeliefNode, un peu comme ce que vous avez décrit avec un nœud supplémentaire entre BeliefNodes, un LinkMatrix. De cette façon, j'ai choisi de choisir le type de risque, je suis en utilisant le type de LinkMatrix que j'utilise. Cela rend plus facile pour expliquer ce que la croyance réseau est en train de faire par la suite ainsi que garde le calcul plus simple.

Tout sous-classement ou des changements que je ferais à la base BeliefNode serait pour le regroupement des variables continues, plutôt que de changer les règles de propagation de nœud ou associations.

J'ai décidé de les garder toutes les données à l'intérieur de la BeliefNode, et fixe des données dans le LinkedMatrix. Cela a à voir avec veillant à ce que j'ai à assurer la pureté de la croyance des mises à jour avec un minimum d'activité sur le réseau. Cela signifie que mon BeliefNode magasins:

  • un tableau de références les enfants, ainsi que les probabilités filtrées provenant de chaque enfant et le lien de la matrice qui est en train de faire le filtrage de l'enfant
  • un tableau de parent références, avec l'filtré avant la cote à venir de chacun des parents et le lien de la matrice qui est en train de faire le filtrage pour que les parent
  • les combinés de la probabilité que le nœud
  • le combiné avant cote du nœud
  • le résultat de croyance, ou de la probabilité a posteriori
  • une liste ordonnée des attributs de tous les cotes et les probabilités respecter

Le LinkMatrix peut être construit avec un certain nombre de différents algorithmes, en fonction de la nature de la relation entre les nœuds. Tous les modèles que vous décrivez serait juste différentes classes que vous auriez à utiliser. Probablement la meilleure chose à faire est de défaut d'un ou de-porte, et puis choisir d'autres façons de gérer les LinkMatrix si nous avons une relation spéciale entre les nœuds.

J'utilise MongoDB pour la persistance et la mise en cache. - Je accéder à ces données à l'intérieur d'un evented modèle pour la vitesse et asynchrone d'accès. Cela rend le réseau assez performant, tout en ayant la possibilité d'être très grand si elle doit l'être. Aussi, depuis que je suis à l'aide de Mongo de cette façon, je peux facilement créer un nouveau contexte pour la même base de connaissances. Ainsi, par exemple, si j'ai un arbre diagnostique, certains du diagnostic à l'appui d'un diagnostic d'un patient, les symptômes et les tests. Ce que j'ai à faire est de créer un contexte pour le patient, avant de se propager mes croyances sur la base des preuves de ce patient particulier. De même, si un médecin a dit qu'un patient est susceptible rencontrez les deux ou de plusieurs maladies, alors je pouvais changer une partie de mon lien matrices à propager la croyance des mises à jour de manière différente.

Si vous ne souhaitez pas utiliser quelque chose comme Mongo pour votre système, mais vous prévoyez d'avoir plus d'un consommateur de travail sur les connaissances de base, vous aurez besoin d'adopter une sorte de système de mise en cache pour vous assurer que vous travaillez sur des nœuds mis à jour à tout moment.

Mon travail est de l'open source, de sorte que vous pouvez suivre si vous le souhaitez. C'est tous les Rubis, de sorte qu'il serait similaire à votre Python, mais pas nécessairement d'une baisse-dans le remplacement. Une chose que j'aime au sujet de ma conception, c'est que toutes les informations nécessaires à l'homme pour interpréter les résultats peuvent être trouvés dans les nœuds eux-mêmes, plutôt que dans le code. Cela peut être fait dans les descriptions qualitatives, ou dans la structure du réseau.

Donc, voici quelques différences importantes que j'ai avec votre design:

  • Je n'ai pas calculer la probabilité modèle à l'intérieur de la classe, mais plutôt entre les nœuds, à l'intérieur du lien de la matrice. De cette façon, je n'ai pas le problème de la combinaison de plusieurs fonctions de probabilité à l'intérieur de la même classe. Je n'ai pas aussi le problème d'un modèle contre un autre, je peux utiliser deux contextes différents pour la même base de connaissances et de comparer les résultats.
  • Je suis en ajoutant beaucoup de transparence en rendant les décisions humaines apparente. I. e., si je décide d'utiliser une valeur par défaut ou la porte de l'entre deux nœuds, je sais que quand j'ai ajouté que, et que c'était juste une décision par défaut. Si je reviens plus tard et changer le lien de la matrice et de re-calcul de la base de connaissances, j'ai une remarque à propos de pourquoi je l'ai fait, plutôt que de simplement une application qui a choisi une méthode plutôt qu'une autre. Vous pourriez avoir votre consommateurs de prendre des notes au sujet de ce genre de chose. Cependant, vous le résoudre, c'est probablement une bonne idée d'obtenir le pas-sage de dialogue de la part de l'analyste à propos de pourquoi ils mettent les choses d'une façon plutôt qu'un autre.
  • J'ai peut-être plus explicite sur le sujet avant de cotes et les probabilités. Je ne sais pas pour sûr à ce sujet, j'ai juste vu que vous étiez à l'aide de différents modèles de changer votre probabilité de chiffres. Beaucoup de ce que je dis peut être complètement hors de propos, si votre modèle pour le calcul de la partie postérieure croyances ne se décompose pas de cette façon. J'ai l'avantage d'être en mesure de faire trois asynchrone étapes qui peuvent être appelées dans un ordre quelconque: passer changé les probabilités du réseau, col modifié avant la cote vers le bas le réseau, et re-calculer le combiné croyance (probabilité a posteriori) du nœud lui-même.

Une grosse mise en garde: certaines de quoi je parle n'a pas encore été dévoilé. J'ai travaillé sur les choses que je suis en train de parler jusqu'à environ 2:00 ce matin, il est donc définitivement actuelle et certainement de faire régulièrement de l'attention de ma part, mais ce n'est pas à la disposition du public pour l'instant. Puisque c'est une passion pour moi, je serais heureux de répondre à toutes vos questions ou de travailler ensemble sur un projet si vous le souhaitez.

3voto

Roberto Lupi Points 21

Le Mozart/Oz3 contraintes basé sur le système d'inférence résout un problème similaire: vous décrivez votre problème en termes de contraintes sur les finis, les variables du domaine des contraintes, diffuseurs et distributeurs, les fonctions de coût. Lorsque plus d'inférence est possible, mais il y a encore indépendant des variables, on utilise les fonctions de coût de diviser le problème de l'espace sur le unbound variable qui, très probablement, réduit les coûts de recherche: qui est, si X est entre [a,c] est une variable, et c (a < b < c) est le point le plus susceptible de réduire les coûts de recherche, vous vous retrouvez avec deux instances de problème où X est compris entre [a,b] et, dans l'autre cas, X est compris entre [b,c]. Mozart n'cette élégante puisqu'elle réifie variable de liaison comme une première classe de l'objet (ce qui est très utile, car Mozart est omniprésente concurrente et distribuée, pour déplacer un problème d'espace à un autre nœud). Dans sa mise en œuvre, je pense qu'il emploie un copier-sur-stratégie d'écriture.

Vous pouvez certainement mettre en œuvre une copie sur écriture schéma dans une base de graphe de la bibliothèque (astuce: numpy utilise diverses stratégies pour minimiser la copie; si vous basez votre représentation graphique sur elle, vous pouvez obtenir une copie sur écriture sémantique gratuitement) et à atteindre vos objectifs.

2voto

Mr. White Points 11

Je ne suis pas trop familier avec les Réseaux Bayésiens, alors j'espère que le suivant est utile:

Dans le passé, j'avais apparemment un problème similaire avec un Processus Gaussien régresseur, au lieu d'un classificateur bayésien.

J'ai fini par l'utilisation de l'héritage, qui fonctionné très bien. Tous les modèles, les paramètres à utiliser sont définis avec le constructeur. La calculer() les fonctions sont virtuels. Une cascade de différentes méthodes (par exemple, un résumé de la méthode qui combine un nombre arbitraire d'autres méthodes) travaille aussi bien de cette façon.

2voto

Matt Points 953

Je pense que vous devez vous poser quelques questions qui influent sur la conception.

  1. Combien de fois allez-vous ajouter des modèles?
  2. Sont des consommateurs de votre bibliothèque prévu d'ajouter de nouveaux modèles?
  3. Quel pourcentage des utilisateurs est l'ajout de modèles vs ce que pour cent de l'aide existants?

Si la plupart du temps sera consacré à des modèles existants et de nouveaux modèles seront moins commun, l'héritage est probablement la conception que j'allais utiliser. Il rend la documentation facile à structure et le code qui utilise, il sera facile à comprendre.

Si le but principal de la bibliothèque est de fournir une plate-forme d'expérimentation de différents modèles, alors je prendrais le graphique avec les propriétés que la carte de foncteurs pour le calcul des choses en se basant sur les parents. La bibliothèque serait plus complexe et création graphique serait plus complexe, mais il serait bien plus puissant que ça permettrait de faire de l'hybride de graphiques de modifier le calcul foncteur basé sur les nœuds.

Indépendamment de ce que la conception finale vous travaillez vers, je voudrais commencer par une simple classe-mise en oeuvre de la conception. Obtenir le passage d'un ensemble de tests automatisés, puis refactoriser dans le plus complet de conception après que ce soit fait. Aussi, n'oubliez pas de contrôle de version ;-)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X