Last active
December 17, 2017 13:59
-
-
Save Syncrossus/9649bf667502faeda938f9fb3586a4c9 to your computer and use it in GitHub Desktop.
Small Single-Attribute Bayesian network classifier. Sorry code is in French, intended recepient is French.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Apprenant: | |
""" | |
Classe modelisant un apprenant bayesien | |
Attributs : | |
classes : classes identifiees dans la base d'apprentissage | |
valAttr : valeurs que peut prendre l'attribut des objets classables | |
tableau : Chaque ligne est une classe, chaque colonne une valeur d'attribut. | |
Chaque cellule contient l'effectif de la base d'apprentissage correspondant. | |
ex : | |
|1.6|1.7|1.8|1.9 | |
C1| 5 | 3 | 2 | 0 | |
C2| 0 | 2 | 3 | 5 | |
Ce tableau signifie que la base d'apprentissage contient : | |
- 5 objets de classe C1 de valeur 1.6 | |
- 3 objets de classe C1 de valeur 1.7 | |
- ... | |
- 5 objets de classe C2 de valeur 1.9 | |
Ce tableau est en realite un dictionnaire de maniere a ce que les classes | |
et les valeurs puissent ne pas etre des nombres entiers | |
probasAPriori : un tableau contenant la probabilite a priori de chaque classe | |
probasAPost : une matrice des probabilites a posteriori correspondant exactement a self.tableau mais avec | |
chaque valeur divisee par l'effectif appartenant a la classe dans la base d'apprentissage | |
""" | |
def __init__(self, baseApprentissage): | |
""" | |
:param baseApprentissage: une liste d'ObjetAClasser avec la classe deja definie | |
""" | |
self.classes = [] | |
self.valAttr = [] | |
for i in baseApprentissage: | |
if i.classe not in self.classes: | |
self.classes.append(i.classe) | |
if i.attribut not in self.valAttr: | |
self.valAttr.append(i.attribut) | |
self.tableau = {} | |
for i in self.classes: | |
for j in self.valAttr: | |
self.tableau[i,j]=0 | |
for i in baseApprentissage: | |
self.tableau[i.classe, i.attribut] += 1 | |
self.probasAPriori = self.calculerProbaAPriori() | |
self.probasAPost = self.calculerProbaAPost() | |
def calculerProbaAPriori(self): | |
""" | |
:return: Le tableau de probabilites a priori pour chaque classe (est appele par le constructeur) | |
""" | |
somme = sum(self.tableau.values()) | |
effectifsClasses = [0 for i in self.classes] | |
classeCourante = 0 | |
for i in self.classes: | |
for j in self.valAttr: | |
effectifsClasses[classeCourante] += self.tableau[i, j] | |
classeCourante += 1 | |
return [i / somme for i in effectifsClasses] | |
def calculerProbaAPost(self): | |
""" | |
:return: Le tableau de probabilites a posteriori pour chaque paire (classe, valeur) | |
(est appele par le constructeur) | |
""" | |
probaAPost = self.tableau.copy() | |
effectifsAttr = [0 for i in self.valAttr] | |
attrCourant = 0 | |
for j in self.valAttr: | |
for i in self.classes: | |
effectifsAttr[attrCourant] += self.tableau[i, j] | |
for i in self.classes: | |
probaAPost[i, j] /= effectifsAttr[attrCourant] | |
attrCourant += 1 | |
return probaAPost | |
def classer(self, obj): | |
""" | |
:param obj: objet a classer de type ObjetAClasser | |
:return: la classe que l'apprenant determine pour l'objet | |
""" | |
#on calcule la probabilite d'appartenance a chaque classe | |
probasAppartenance = [] | |
for i in self.classes: | |
# la probabilite d'appartenance a une classe est le produit de la probabilite a posteriori par la proba a priori | |
probasAppartenance.append(self.probasAPost[i, obj.attribut] * self.probasAPriori[self.classes.index(i)]) | |
#on trouve l'indice du max dans le tableau de probabilites d'appartenance | |
#par construction, cet indice sera egalement l'indice de la classe correspondante dans le tableau de classes | |
# (par propriete de determinisme du parcours des tableaux en python, ceci ne serait pas vrai avec un dictionnaire) | |
return self.classes[probasAppartenance.index(max(probasAppartenance))] | |
class ObjetAClasser: | |
""" | |
Cette classe modelise un objet que l'apprenant doit classer. | |
Attributs: | |
attribut: Les objets a classer n'ont qu'un seul attribut, qui peut prendre n'importe quelle valeur. | |
Generaliser l'apprenant pour gerer n attributs aurait bien sur ete possible, mais aurait requis une | |
dimension de plus dans le tableau ce qui aurait ajoute beaucoup de complexite pour un benefice | |
pedagogique quasiment nul. | |
classe: La classe de l'objet. Doit etre precisee si l'objet est destine a faire partie de la base d'apprentissage. | |
Ce programme a ete fait avec l'hypothese que la classe est de type entier, il pourrait ne pas fonctionner | |
ce n'est pas le cas | |
""" | |
def __init__(self, attribut, classe=-1): | |
self.attribut = attribut | |
self.classe = classe | |
if __name__ == '__main__': | |
""" | |
Ici on cree un apprenant avec la base d'apprentissage presentee en exemple dans la classe Apprenant, a savoir : | |
|1.6|1.7|1.8|1.9 <----- valeurs pour l'attribut | |
1| 5 | 3 | 2 | 0 <--.-- classes | |
2| 0 | 2 | 3 | 5 <--' | |
Cet exemple est bien sur le meme exemple que celui vu en cours, a savoir que les valeurs sont des tailles (en m) | |
et les classes sont des sexes (masculin / feminin) | |
""" | |
app = Apprenant([ObjetAClasser(1.6, 1), ObjetAClasser(1.6, 1), ObjetAClasser(1.6, 1), ObjetAClasser(1.6, 1), ObjetAClasser(1.6, 1), | |
ObjetAClasser(1.7, 1), ObjetAClasser(1.7, 1), ObjetAClasser(1.7, 1), ObjetAClasser(1.7, 2), ObjetAClasser(1.7, 2), | |
ObjetAClasser(1.8, 1), ObjetAClasser(1.8, 1), ObjetAClasser(1.8, 2), ObjetAClasser(1.8, 2), ObjetAClasser(1.8, 2), | |
ObjetAClasser(1.9, 2), ObjetAClasser(1.9, 2), ObjetAClasser(1.9, 2), ObjetAClasser(1.9, 2), ObjetAClasser(1.9, 2)]) | |
#Puis on classe quatre objets (un pour chaque valeur possible d'attribut) | |
#sans preciser la classe puisqu'elle ne nous interesse pas lorsqu'on classe | |
print(app.classer(ObjetAClasser(1.6))) | |
print(app.classer(ObjetAClasser(1.7))) | |
print(app.classer(ObjetAClasser(1.8))) | |
print(app.classer(ObjetAClasser(1.9))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment