Indépendances conditionnelles et réseaux bayésiens
Partie obligatoire
Dans ce TME, l'objectif est d'apprendre des réseaux bayésiens à partir de bases de données. Hormis la base asia, un exemple jouet relativement petit qui vous permettra de mettre au point les différents algorithmes du TME, et car, les autres bases correspondront à des distributions de probabilité de tailles raisonnables :
nom de la base | provenance | nombre d'événements élémentaires |
---|---|---|
asia | BN repository | 256 |
alarm | BN repository | 1016 |
adult | UCI machine learning repository | 1012 |
car | UCI machine learning repository | 6912 |
agaricus-lepiota | UCI machine learning repository | 1016 |
Apprendre un réseau bayésien consiste à apprendre sa structure graphique ainsi que les paramètres de ses distributions de probabilité conditionnelles. Pour réaliser la deuxième tâche, il suffit d'estimer les paramètres de chaque distribution conditionnelle par maximum de vraisemblance, comme vous l'avez fait dans le TME 3. Ici, nous nous focaliserons donc plutôt sur l'apprentissage de structure. Celle-ci reflétant des indépendances conditionnelles entre variables aléatoires, vous devrez exploiter des tests d'indépendance du {$\chi^2$} afin d'obtenir des structures graphiques les moins denses possibles (en termes de nombres d'arcs). Ainsi, alarm représente une distribution jointe de plus de 1016 événements élémentaires mais, quand cette distribution est décomposée grâce au graphe ci-dessous (les noeuds représentant les variables aléatoires), elle peut être décrite (sans perte d'informations) à l'aide de seulement 752 paramètres. Comme nous l'avons vu en cours, cette représentation permet également d'effectuer très rapidement des calculs probabilistes.

1. Lecture des données
Dans le code ci-dessous, la fonction read_csv : string -> (string np.array, int np.2D-array, dico{string -> int} np.array)
vous permettra de lire les données des bases sur lesquelles vous allez travailler, et de les organiser sous une forme adéquate. Par exemple, une base de données est un fichier de la forme:
X_0,X_1,X_2,X_3 haut,gauche,petit,bas bas,droite,grand,gauche bas,gauche,moyen,bas
Dans cette base, nous avons 4 variables aléatoires nommées X_0, X_1, X_2, et X_3, et 3 enregistrements qui représentent des instanciations (observées) de ces 4 variables. Ainsi, X_0 a pour valeurs haut, bas et bas, X_1 a pour valeurs gauche, droite, gauche, etc.
La fonction read_csv prend en argument le nom d'un fichier CSV contenant une base de données et renvoie un triplet composé de :
- 1 tableau numpy de strings contenant les noms des variables aléatoires. Par exemple, pour la base ci-dessus, ce tableau correspond à:
n.array (['X_0', 'X_1', 'X_2', 'X_3'])
- un tableau numpy 2D contenant les données du fichier CSV encodées sous forme numérique (les valeurs des variables aléatoires sont transformées en nombres entiers): chaque ligne de ce tableau représente les intanciations d'une variable aléatoire et chaque colonne représente un enregistrement de la base de données, c'est-à-dire une instanciation/observation de toutes les variables aléatoires. Pour la base ci-dessus, nous obtiendrions le tableau ci-dessous (la signification des nombres est indiquée dans le dictionnaire précisé plus bas):
np.array ( [ [0, 1, 1], # instanciations de la variable X_0 [0, 1, 0], # instanciations de la variable X_1 [0, 1, 2], # instanciations de la variable X_2 [0, 1, 0]] ) # instanciations de la variable X_3
- un tableau numpy de dictionnaires faisant la correspondance, pour chaque variable aléatoire, entre l'encodage numérique du tableau 2D ci-dessus et les données du fichier CSV (le 1er dictionnaire correspond à la variable de la 1ère colonne du CSV, le 2ème dictionnaire à celle de la 2ème colonne, etc.). Ainsi, le dictionnaire est égal à :
np.array( [ {'haut': 0, 'bas': 1}, # encodage variable X_0 {'gauche': 0, 'droite': 1}, # encodage variable X_1 {'petit': 0, 'grand': 1, 'moyen': 2 }, # encodage variable X_2 {'bas': 0, 'gauche': 1} ] ) # encodage variable X_3
Téléchargez le fichier 2015_tme5_asia.csv et lisez-le à l'aide de la fonction read_csv ci-dessous: la dernière instruction, names, data, dico = read_csv ( "2015_tme5_asia.csv" )
, vous permettra de récupérer, séparément, les trois champs du triplet renvoyé par la fonction read_csv.
import numpy as np
# fonction pour transformer les données brutes en nombres de 0 à n-1
def translate_data ( data ):
# création des structures de données à retourner
nb_variables = data.shape[0]
nb_observations = data.shape[1] - 1 # - nom variable
res_data = np.zeros ( (nb_variables, nb_observations ), int )
res_dico = np.empty ( nb_variables, dtype=object )
# pour chaque variable, faire la traduction
for i in range ( nb_variables ):
res_dico[i] = {}
index = 0
for j in range ( 1, nb_observations + 1 ):
# si l'observation n'existe pas dans le dictionnaire, la rajouter
if data[i,j] not in res_dico[i]:
res_dico[i].update ( { data[i,j] : index } )
index += 1
# rajouter la traduction dans le tableau de données à retourner
res_data[i,j-1] = res_dico[i][data[i,j]]
return ( res_data, res_dico )
# fonction pour lire les données de la base d'apprentissage
def read_csv ( filename ):
data = np.loadtxt ( filename, delimiter=',', dtype=np.str ).T
names = data[:,0].copy ()
data, dico = translate_data ( data )
return names, data, dico
# names : tableau contenant les noms des variables aléatoires
# data : tableau 2D contenant les instanciations des variables aléatoires
# dico : tableau de dictionnaires contenant la correspondance (valeur de variable -> nombre)
names, data, dico = read_csv ( "2015_tme5_asia.csv" )
2. Statistique du {$\chi^2$} conditionnel
Soit deux variables aléatoires {$X$} et {$Y$}. Appelons {$N_{xy}$}, {$N_x$} et {$N_y$}, respectivement, le nombre d'occurrences du couple {$(X=x,Y=y)$} et des singletons {$X=x$} et {$Y=y$} dans la base de données. Alors, comme indiqué dans le cours 5, la statistique du {$\chi^2$} de {$X$} et {$Y$} est égale à :
{$$\chi^2_{X,Y} = \sum_x\sum_y\frac{\left(N_{xy} - \frac{N_x \times N_y}{N}\right)^2}{\frac{N_x \times N_y}{N}}$$}
où {$N$} représente le nombre de lignes de la base de données. Cette formule permet de tester l'indépendance entre les deux variables {$X$} et {$Y$}. On peut aisément généraliser celle-ci pour tester des indépendances conditionnellement à un ensemble de variables {$\mathbf{Z}$}:
{$$\chi^2_{X,Y|\mathbf{Z}} = \sum_x\sum_y\sum_{\mathbf{z}}\frac{\left(N_{xy\mathbf{z}} - \frac{N_{x\mathbf{z}} \times N_{y\mathbf{z}}}{N_{\mathbf{z}}}\right)^2}{\frac{N_{x\mathbf{z}} \times N_{y\mathbf{z}}}{N_{\mathbf{z}}}}$$}
où {$N_{xy\mathbf{z}}$}, {$N_{x\mathbf{z}}$}, {$N_{y\mathbf{z}}$} et {$N_{\mathbf{z}}$} représentent, respectivement, le nombre d'occurrences du triplet {$(X=x,Y=y,\mathbf{Z} = \mathbf{z})$}, des couples {$(X=x,\mathbf{Z} = \mathbf{z})$} et {$(Y=y,\mathbf{Z} = \mathbf{z})$}, et du singleton {$\mathbf{Z} = \mathbf{z}$}. Ainsi, si {$\mathbf{Z}$} est un ensemble de 3 variables aléatoires {$(A,B,C)$}, les valeurs {$\mathbf{z}$} seront des triplets {$(a,b,c)$}.
Afin de vous aider à calculer ces {$\chi^2$}, vous pourrez utiliser la fonction create_contingency_table : int np.2D-array x dico{string -> int} np.array x int x int x int list -> (int, np.2D-array) np.array
ci-dessous. Celle-ci prend en argument le tableau 2D numpy data
et le tableau de dictionnaires dico
retournés à la fin de la question 1, ainsi que l'index x
d'une variable aléatoire (0 = 1ère variable aléatoire (celle de la 1ère ligne de data
), 1 = 2ème variable, etc.), l'index y
d'une autre variable et une liste z
d'index d'autres variables aléatoires. Elle renvoie un tableau de couples ({$N_{\mathbf{z}}, T_{X,Y,\mathbf{z}})$}, pour tous les {$\mathbf{z} \in\mathbf{Z}$}, où:
- {$N_{\mathbf{z}}$} représente le nombre d'occurences de {$Z=z$} dans la base de données. Par exemple, si la base de données est la suivante :
X_0,X_1,X_2,X_3 haut,gauche,petit,bas bas,droite,grand,gauche bas,gauche,moyen,bas
data
est égal à :
data = np.array ( [ [0, 1, 1], # instanciations de la variable X_0 [0, 1, 0], # instanciations de la variable X_1 [0, 1, 2], # instanciations de la variable X_2 [0, 1, 0]] ) # instanciations de la variable X_3
( data, dico, 0, 2, [3] )
renverra le tableau:
resultat = array([ (2, array([[ 1., 0., 0.], # Z = 0 => N_{Z=0} = 2 [ 0., 0., 1.]])), (1, array([[ 0., 0., 0.], # Z = 1 => N_{Z=1} = 1 [ 0., 1., 0.]])) ])
[3]
indique que {$\mathbf{Z}$} est constitué uniquement de la quatrième variable de la base, autrement dit X_3. La dernière ligne du tableau data
indique les instanciations de X_3 et l'on peut observer que la valeur 0 apparaît 2 fois et la valeur 1 apparaît une fois. On a donc {$N_{Z=0} = 2$} et {$N_{Z=1} = 1$}. On peut observer que les valeurs de {$N_{\mathbf{Z}}$} sont bien les premiers éléments des couples de resultat
. Lorsque {$\mathbf{Z} = \emptyset$}, resultat
est un tableau avec un seul couple dont le premier élément correspond précisément à {$N$}, le nombre d'enregistrements de la base de données.
- {$T_{X,Y,\mathbf{z}}$} est un tableau 2D contenant le nombre d'occurrences {$N_{xy\mathbf{z}}$} des couples {$(X=x,Y=y)$} lorsque {$\mathbf{Z}=\mathbf{z}$}. La première dimension de ce tableau (les lignes) correspondent aux différentes valeurs de {$X$} et la deuxième (les colonnes) à celles de {$Y$}. Ainsi, le tableau en haut à droite de
resultat
est obtenu de la manière suivante: ce tableau correspond à des occurrences de {$(X,Y)$} lorsque {$\mathbf{Z}=0$}. on commence donc par extraire dedata
le sous-tableau correspondant à la première et à la troisième colonne (les colonnes où X_3=0) et on ne retient que les lignes correspondant à X_0 et X_2 (cf. les paramètres 0 et 2 passés en arguments de create_contingency_table). On obtient donc le sous-tableau:
np.array ( [ [0, 1], # instanciations de la variable X_0 [0, 2]] ) # instanciations de la variable X_2
resultat
.
En utilisant la structure retournée par la fonction create_contingency_table, écrivez une fonction sufficient_statistics: int np.2D-array x dico{string -> int} np.array x int x int x int list -> float
qui prend les mêmes arguments que la fonction create_contingency_table et qui renvoie la valeur de {$\chi^2_{X,Y|\mathbf{Z}}$}. Vous pourrez tirer profit du fait que {$N_{x\mathbf{z}} = \sum_{y} N_{xy\mathbf{z}}$} et {$N_{y\mathbf{z}} = \sum_{x} N_{xy\mathbf{z}}$}, ce qui revient à faire des sommes sur chaque ligne ou chaque colonne des tableaux {$T_{X,Y,\mathbf{z}}$}. Attention : il peut arriver que certains {$N_{\mathbf{z}}$} soient égaux à 0. Dans ce cas, vous ne tiendrez pas compte des {$N_{xy\mathbf{z}}$}, {$N_{x\mathbf{z}}$} et {$N_{y\mathbf{z}}$} correspondants dans la formule de {$\chi^2_{X,Y|\mathbf{Z}}$} (car vous feriez des divisions par 0, ce qui est mal).
# tableau de contingence de (x,y) | z
def create_contingency_table ( data, dico, x, y, z ):
# détermination de la taille de z
size_z = 1
offset_z = np.zeros ( len ( z ) )
j = 0
for i in z:
offset_z[j] = size_z
size_z *= len ( dico[i] )
j += 1
# création du tableau de contingence
res = np.zeros ( size_z, dtype = object )
# remplissage du tableau de contingence
if size_z != 1:
z_values = np.apply_along_axis ( lambda val_z : val_z.dot ( offset_z ),
1, data[z,:].T )
i = 0
while i < size_z:
indices, = np.where ( z_values == i )
a,b,c = np.histogram2d ( data[x,indices], data[y,indices],
bins = [ len ( dico[x] ), len (dico[y] ) ] )
res[i] = ( indices.size, a )
i += 1
else:
a,b,c = np.histogram2d ( data[x,:], data[y,:],
bins = [ len ( dico[x] ), len (dico[y] ) ] )
res[0] = ( data.shape[1], a )
return res
Vous pourrez vérifier la validité de vos calculs: en utilisant la base de données "2015_tme5_asia.csv", vous devriez obtenir les résultats suivants:
appel de la fonction | résultat |
---|---|
sufficient_statistics ( data, dico, 1,2,[3]) | 3.9466591186668296 |
sufficient_statistics ( data, dico, 0,1,[2,3]) | 16.355207462350094 |
sufficient_statistics ( data, dico, 1,3,[2]) | 81.807449348140295 |
sufficient_statistics ( data, dico, 5,2,[1,3,6]) | 1897.0 |
sufficient_statistics ( data, dico, 0,7,[4,5]) | 3.2223237760949699 |
sufficient_statistics ( data, dico, 2,3,[5]) | 130.0 |
3. Statistique du {$\chi^2$} et degré de liberté
Modifiez votre fonction sufficient_statistics afin qu'elle ne renvoie plus seulement {$\chi^2_{X,Y|\mathbf{Z}}$} mais plutôt un couple ({$\chi^2_{X,Y|\mathbf{Z}}$},DoF), où DoF est le nombre de degrés de liberté de votre statistique. Celui-ci est égal à :
{$$(|X|-1) \times (|Y|-1) \times |\{\mathbf{z} : N_{\mathbf{z}} \neq 0\}| $$}
où {$|X|$} représente le nombre de valeurs possibles que peut prendre la variable {$X$}, autrement dit, c'est la taille de son dictionnaire. Le dernier terme de l'équation est simplement le nombre de {$N_{\mathbf{z}}$} différents de 0.
Vous pourrez vérifier la validité de vos calculs: en utilisant la base de données "2015_tme5_asia.csv", vous devriez obtenir les résultats suivants:
appel de la fonction | résultat |
---|---|
sufficient_statistics ( data, dico, 1,2,[3]) | (3.9466591186668296, 2) |
sufficient_statistics ( data, dico, 0,1,[2,3]) | (16.355207462350094, 3) |
sufficient_statistics ( data, dico, 1,3,[2]) | (81.807449348140295, 2) |
sufficient_statistics ( data, dico, 5,2,[1,3,6]) | (1897.0, 8) |
sufficient_statistics ( data, dico, 0,7,[4,5]) | (3.2223237760949699, 4) |
sufficient_statistics ( data, dico, 2,3,[5]) | (130.0, 2) |
4. Test d'indépendance
En cours, nous avons vu que, pour un risque {$\alpha$} donné, si la statistique {$\chi^2_{X,Y|\mathbf{Z}}$} est inférieure au seuil critique {$c_{\alpha}$} de la loi du {$\chi^2$} à DoF degrés de liberté, alors {$X$} et {$Y$} sont considérés comme indépendants conditionnellement à {$\mathbf{Z}$} ({$X \perp\hspace{-1.7mm}\perp Y | \mathbf{Z}$}). On peut reformuler cette propriété de la manière suivante :
{$$\text{p-value}(\chi^2_{X,Y|\mathbf{Z}}) \geq \alpha \Longleftrightarrow X \perp\hspace{-1.7mm}\perp Y | \mathbf{Z}$$}
La p-value d'un nombre x est l'intégrale de la fonction de densité de la loi du {$\chi^2$} de x à {$+\infty$} (autrement dit, c'est la surface de la partie grisée sur votre table du {$\chi^2$} à partir de l'abscisse x. On a donc p-value{$(c_{\alpha}) = \alpha$}). En statistiques, on considère qu'elle n'a du sens que si les valeurs du tableau de contingence sont toutes supérieures ou égales à 5 (autrement dit, un test d'indépendance du {$\chi^2$} n'est "valide" que si toutes les valeurs du tableau de contingence sont supérieures ou égales à 5). En informatique, on allège souvent cette règle en considérant que le test est valide dès lors que la valeur moyenne des cases est supérieure ou égale à 5. Cet allègement permet de tester la validité du test sans réaliser celui-ci : si le nombre de lignes du CSV est supérieure ou égale à {$d_{min} = 5 \times |X| \times |Y| \times |\mathbf{Z}|$}, le test est considéré comme valide.
Ecrivez une fonction indep_score : int np.2D-array x dico{string -> int} np.array x int x int x int list -> (float,int)
qui, étant donné les mêmes paramètres que ceux de la question précédente, vous renvoie un couple contenant la p-value correspondant à {$\chi^2_{X,Y|\mathbf{Z}}$} ainsi que le nombre de degrés de liberté de cette statistique. Vous testerez au préalable si len ( data[0] ), le nombre de lignes/enregistrements de votre CSV, est supérieur ou non à {$d_{min}$} ; si c'est inférieur, vous renverrez le couple (-1,1), qui représente une indépendance. Vous pourrez vous aider de la fonction scipy.stats.chi2.sf ( x, DoF ) qui renvoie la p-value (x) pour une loi à DoF degrés de liberté.
stats.chi2.sf ( x, DoF )
Vous pourrez vérifier la validité de vos calculs: en utilisant la base de données "2015_tme5_asia.csv", vous devriez obtenir les résultats suivants:
appel de la fonction | résultat |
---|---|
indep_score ( data, dico, 1,3,[]) | 2.38520176938e-19 |
indep = indep_score ( data, dico, 1, 7, []) | 1.12562784979e-10 |
indep = indep_score ( data, dico, 0, 1,[2, 3]) | 0.000958828236575 |
indep = indep_score ( data, dico, 1, 2,[3, 4]) | 0.475266197894 |
Partie optionnelle
5. Meilleur candidat pour être un parent
Ecrivez une fonction best_candidate : int np.2D-array x dico{string -> int} np.array x int x int list x float -> int list
qui, étant donné les tableaux data
et dico
calculés à la question 1, l'index d'une variable aléatoire {$X$}, la liste d'index d'un ensemble de variables aléatoires {$\mathbf{Z}$} et un risque {$\alpha$}, détermine la variable {$Y$} (en fait, l'index de sa colonne dans le CSV), parmi toutes celles à gauche de {$X$} dans le fichier CSV, qui est la plus dépendante de {$X$} conditionnellement à {$\mathbf{Z}$}, autrement dit, celle qui a la plus petite p-value. Si cette p-value est supérieure à {$\alpha$}, cela veut dire que {$\chi^2_{X,Y|\mathbf{Z}}$} est inférieur à {$c_{\alpha}$} et donc que {$Y$} est jugée indépendante de {$X$} conditionnellement à {$\mathbf{Z}$}. Votre fonction renverra une liste vide si {$Y$} est indépendante de {$X$} conditionnellement à {$\mathbf{Z}$}, sinon elle renverra une liste contenant {$Y$}. Vous pourrez tester votre fonction avec {$\alpha$} = 0.05:
appel de la fonction | résultat |
---|---|
best_candidate ( data, dico, 1, [], 0.05 ) | [] |
best_candidate ( data, dico, 4, [], 0.05 ) | [1] |
best_candidate ( data, dico, 4, [1], 0.05 ) | [] |
best_candidate ( data, dico, 5, [], 0.05 ) | [3] |
best_candidate ( data, dico, 5, [6], 0.05 ) | [3] |
best_candidate ( data, dico, 5, [6,7], 0.05 ) | [2] |
6. Création des parents d'un noeud
Ecrivez une fonction create_parents ( data, dico, x, alpha ) qui, étant donné une variable aléatoire x et un niveau de risque alpha, retourne la liste z de ses parents dans le réseau bayésien. L'algorithme est le suivant : partez de z = l'ensemble vide, puis tant que best_candidate ( x, z, alpha ) vous renvoie une liste non vide [y], rajoutez y à z. Lorsque vous sortirez de cette boucle, toutes les autres variables seront indépendantes de x conditionnellement à z.
L'algorithme qui consiste à appliquer, pour chaque noeud/variable aléatoire, votre fonction create_parents correspond, en grande partie, à l'article suivant :
Gregory F. Cooper and Edward Herskovits (1992) "A Bayesian method for the induction of probabilistic networks from data", Machine Learning, Vol. 9, n°4, pp. 309-347.
Vous pourrez tester la validité de votre fonction :
appel de la fonction | résultat |
---|---|
create_parents ( data, dico, 1, 0.05 ) | [] |
create_parents ( data, dico, 4, 0.05 ) | [1] |
create_parents ( data, dico, 5, 0.05 ) | [3, 2] |
create_parents ( data, dico, 6, 0.05 ) | [4, 5] |
7. Apprentissage de la structure d'un réseau bayésien
Ecrivez une fonction learn_BN_structure ( data, dico, alpha ) qui renvoie un tableau contenant, pour chaque noeud, la liste de ses parents. Ainsi, si votre fonction vous renvoie le tableau ci-dessous,
array( [ [], [], [], [1, 0], [1], [3, 2], [4, 5], [5] ] )
les noeud correspondant aux 2 premières colonnes du CSV n'ont pas de parents, le noeud de la 3ème colonne a pour parent celui de la 1ère colonne, etc.
Pour visualiser plus aisément votre structure, utilisez la fonction display_BN ci-dessous. Celle-ci prend en paramètres :
- le tableau des noms des variables aléatoires déterminé à la question 1
- la structure que vous avez calculée avec votre fonction learn_BN_structure
- un nom que vous voulez donner à votre réseau
- un style pour afficher les noeuds
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
style = { "bgcolor" : "#6b85d1", "fgcolor" : "#FFFFFF" }
def display_BN ( node_names, bn_struct, bn_name, style ):
graph = pydot.Dot( bn_name, graph_type='digraph')
# création des noeuds du réseau
for name in node_names:
new_node = pydot.Node( name,
style="filled",
fillcolor=style["bgcolor"],
fontcolor=style["fgcolor"] )
graph.add_node( new_node )
# création des arcs
for node in range ( len ( node_names ) ):
parents = bn_struct[node]
for par in parents:
new_edge = pydot.Edge ( node_names[par], node_names[node] )
graph.add_edge ( new_edge )
# sauvegarde et affaichage
outfile = bn_name + '.png'
graph.write_png( outfile )
img = mpimg.imread ( outfile )
plt.imshow( img )

7. Fin de l'apprentissage et calcul probabiliste
Comme précisé au début du TME, apprendre un réseau bayésien consiste à déterminer sa structure graphique et estimer ses paramètres. Vous avez réalisé la première partie. La deuxième, plus simple, peut se faire par maximum de vraisemblance pour chaque table de probabilité des noeuds conditionnellement à leurs parents, comme dans le TME 3. Utilisez la fonction learn_parameters ci-dessous pour effectuer cette tâche. Cette fonction prend en paramètres la structure graphique que vous avez apprise ainsi que le nom du fichier CSV que vous avez utilisé pour votre apprentissage. Elle renvoie un réseau bayésien à la aGrUM. Pour pouvoir utiliser aGrUM, reportez-vous à la question 7 du TME 2.
import pyAgrum.lib.ipython as gnb
def learn_parameters ( bn_struct, ficname ):
# création du dag correspondant au bn_struct
graphe = gum.DAG ()
nodes = [ graphe.addNode () for i in range ( bn_struct.shape[0] ) ]
for i in range ( bn_struct.shape[0] ):
for parent in bn_struct[i]:
graphe.addArc ( nodes[parent], nodes[i] )
# appel au BNLearner pour apprendre les paramètres
learner = gum.BNLearner ( ficname )
learner.useScoreLog2Likelihood ()
learner.useAprioriSmoothing ()
return learner.learnParameters ( graphe )
Vous pouvez maintenant réaliser des calculs probabilistes :
- affichage de la taille du réseau bayésien
bn = learn_parameters ( bn_struct, ficname )
# affichage de sa taille
print(bn)
- affichage de la table de probabilité conditionnelle d'un noeud du réseau déterminé par son nom (1ère ligne du CSV):
gnb.showPotential( bn.cpt ( bn.idFromName ( 'bronchitis?' ) ) )
- calcul de la probabilité marginale d'un noeud : P('bronchitis?'):
proba = gum.getPosterior ( bn, {}, 'bronchitis?' )
- affichage graphique d'une distribution de probabilité marginale
gnb.showPotential( proba )
- calcul d'une distribution marginale a posteriori : P(bronchitis? | smoking? = true, turberculosis? = false )
8. (Bonus) Autres bases de données
Vous pouvez appliquer vos algorithmes sur des bases un peu plus conséquentes qu'asia:
nom de la base | dataset | nb de lignes de la base | événements élémentaires |
---|---|---|---|
asia | asia dataset | 30000 | 256 |
adult | adult dataset | 30162 | 1012 |
car | car dataset | 1728 | 6912 |
agaricus-lepiota | agaricus-lepiota dataset | 8124 | 1016 |
alarm | alarm dataset | 20000 | 1016 |