Chapitre III: Classification naïve bayésienne

La classification est un apprentissage supervisé; ce qui veut dire, on doit entrainer notre système sur un ensemble de données, ensuite on utilise ce modèle pour classer des données de test.

Ici, on va commencer par présenter la phase de classification avant la phase d’entrainement.

Sommaire

(Retour vers la page principale)

III-1 Classification

Voici le théorème de Bayes:

III-1-bayes

Le problème de classification revient à estimer la probabilité de chaque classe c-i sachant un vecteur de caractéristiques vec-f. Par exemple, on veut estimer la probabilité d’un animal étant: un chien, un chat, une vache ou autre (4 classes) en utilisant quelques caractéristiques: poids, longueur, longueur des pattes et le type de nourriture. En appliquant le théorème de Bayes:

III-1-bayes2

Le dénominateur ne dépend pas de la classe c-i

III-1-bayes3

En supposant l’indépendance entre les critères f-j de vec-f (d’où le nom: naïve):

III-1-bayes4

Les probabilités calculées servent à sélectionner la classe la plus probable sachant un vecteur de caractéristiques donné. Donc, la classe estimée (c ) est celle qui maximise la probabilité conditionnelle.

III-1-bayes5

III-1-bayes6

Techniquement, on utilise l’espace logarithmique puisque le produit des probabilités converge vers zéro.

III-1-bayes7

(Sommaire)

III-2 Apprentissage

Étant donné un ensemble de données d’entrainement avec N échantillons, la probabilité d’apparition d’une classe c-i est estimée comme étant le nombre de ses échantillons divisé par le nombre total des échantillons d’entrainement.

III-2-pci

La probabilité de chaque caractéristique f-j sachant une classe c-i est estimée selon le type de ces valeurs: discrètes, binaires ou continues.

Loi multinomiale

Lorsque les valeurs des caractéristiques sont discrètes, on utilise la loi multinomiale. Par exemple, la couleur des cheveux avec les valeurs: brun, auburn, châtain, roux, blond vénitien, blond et blanc. La probabilité d’une caractéristique f-j sachant une classe c-i est le nombre des occurrences de ce critère dans la classe ( III-2-mult1 ) divisé par le nombre de ces occurrences dans tout l’ensemble de données.

III-2-mult2

Certaines caractéristiques peuvent ne pas se figurer dans une classe donnée, ce qui va donner une probabilité nulle. Pour remédier à ce problème, on peut utiliser une fonction de lissage comme le lissage de Lidstone.

III-2-mult3

Où: |vec-f| est le nombre des caractéristiques. Alpha: est un nombre dans l’intervalle ]0, 1]. Lorsque sa valeur égale à 1, on appelle ça le laissage de Laplace.

Loi de Bernoulli

Lorsque les valeurs des caractéristiques sont binaires, on utilise la loi de Bernoulli. Par exemple,

…TODO: Complete one day!!

Loi normal

Lorsque les valeurs des caractéristiques sont continues, on utilise la loi normale (loi gaussienne). Par exemple, le poids, le prix, etc. En se basant sur les données d’entrainement avec N échantillons, on calcule l’espérance μ et la variance σ² de chaque caractéristique f-j et chaque classe c-i.

III-2-mu

III-2-sigma

Donc, la probabilité qu’une caractéristique f-j ait une valeur x sachant une classe c-i suit la loi normale.

III-2-normal

(Sommaire)

III-3 Exemples

Classifieur naïf bayésien suivant la loi normal

Empruntons l’exemple de Wikipédia

On veut classer une personne donnée en féminin ou masculin selon la taille, le poids et la pointure. Donc, le vecteur de caractéristique vec-f={taille, poids, pointure} et le vecteur de classes vec-c={féminin, masculin}. Les données d’apprentissage contiennent 8 échantillons.

Sexe Taille (cm) Poids (kg) Pointure (cm)
masculin 182 81.6 30
masculin 180 86.2 28
masculin 170 77.1 30
masculin 180 74.8 25
féminin 152 45.4 15
féminin 168 68.0 20
féminin 165 59.0 18
féminin 175 68.0 23

Apprentissage: La phase d’apprentissage consiste à calculer l’espérance et la variance de chaque caractéristique et classe.

P(masculin) = 4/8 = 0.5

P(féminin) = 4/8 = 0.5

Sexe μ (taille) σ² (taille) μ (poids) σ² (poids) μ (pointure) σ² (pointure)
masculin 178 29.333 79.92 25.476 28.25 5.5833
féminin 165 92.666 60.1 114.04 19.00 11.333

test: On a un échantillons avec les caractéristiques suivantes {taille=183, poids=59, pointure=20}. On veut savoir si c’est féminin ou masculin.

…TODO: continue

…TODO: example about sentiment analysis using multinomial bayes

(Sommaire)

III-4 Avantages

Les classifieurs naïfs bayésiens, malgré leurs simplicité, ont des points forts:

(Sommaire)

III-5 Limites

Les classifieurs naïfs bayésiens certes sont populaires à cause de leur simplicité. Mais, une telle simplicité vient avec un cout.

(Sommaire)

III-6 un peu de programmation

Dans cet exercice, on veut classifier les champignons comme toxiques ou non. On va utiliser l’ensemble de données mushroom classification pour classer les champignons comme comestibles ou toxiques en se basant sur 22 caractéristiques nominales. Le fichier est de type CSV contenant 8124 échantillons. Voici la description des colonnes:

  1. classe: (e) [edible] comestible; (p) [poisonous] toxique
  2. chapeau-forme: (b) [bell]; (c) [conical] conique; (x) [convex] convexe; (f) [flat] plat; (k) [knobbed] noué; (s) [sunken] enfoncé
  3. chapeau-surface: (f) [fibrous] fibreuse; (g) [grooves] rainures; (y) [scaly] écailleuse; (s) [smooth] lisse
  4. chapeau-couleur: brown=n, buff=b, cinnamon=c, gray=g, green=r,
  5. ecchymoses: true=t, false=f
  6. odeur: almond=a, anise=l, creosote=c, fishy=y, foul=f, musty=m, none=n, pungent=p, spicy=s
  7. branchie-attachement: attached=a,descending=d,free=f,notched=n
  8. branchie-espacement: close=c,crowded=w,distant=d
  9. branchie-taille: broad=b,narrow=n
  10. branchie-couleur: black=k,brown=n,buff=b,chocolate=h,gray=g, green=r,orange=o,pink=p,purple=u,red=e, white=w,yellow=y
  11. tige-forme: enlarging=e,tapering=t
  12. tige-racine: bulbous=b,club=c,cup=u,equal=e, rhizomorphs=z,rooted=r,missing=?
  13. tige-surface-dessus-anneau: fibrous=f,scaly=y,silky=k,smooth=s
  14. tige-surface-dessous-anneau: fibrous=f,scaly=y,silky=k,smooth=s
  15. tige-couleur-dessus-anneau: brown=n,buff=b,cinnamon=c,gray=g,orange=o, pink=p,red=e,white=w,yellow=y
  16. tige-couleur-dessous-anneau: brown=n,buff=b,cinnamon=c,gray=g,orange=o, pink=p,red=e,white=w,yellow=y
  17. voile-type: partial=p,universal=u
  18. voile-couleur: brown=n,orange=o,white=w,yellow=y
  19. anneau-nombre: none=n,one=o,two=t
  20. anneau-type: cobwebby=c,evanescent=e,flaring=f,large=l, none=n,pendant=p,sheathing=s,zone=z
  21. spore-couleur: black=k,brown=n,buff=b,chocolate=h,green=r, orange=o,purple=u,white=w,yellow=y
  22. population: abundant=a,clustered=c,numerous=n, scattered=s,several=v,solitary=y
  23. habitat: grasses=g,leaves=l,meadows=m,paths=p, urban=u,waste=w,woods=d

Tester s’il y a des valeurs manquantes

Consulter le fichier codes/bayes/tester.py

Avant tout, on importe le fichier, et on affiche les 6 premières lignes (plus la première qui contient les noms des caractéristiques) afin de vérifier l’importation nos données.

import pandas

#lire le fichier csv
data = pandas.read_csv("champignons.csv")
#affichier les 6 premiers échantillons
print data.head(6)

On peut vérifier s’il y a des valeurs manquantes dans les échantillons. Ici, on va afficher le nombre de valeurs manquantes pour chaque caractéristique.

print data.isnull().sum()

On peut afficher, également, les différentes catégories possibles pour une caractéristique donnée. Ici, on veut afficher les classes possibles. Attention! si on utilise un nom de caractéristique qui n’existe pas dans les données, on va avoir une erreur.

print data['classe'].unique()

On peut vérifier le nombre des lignes et des colonnes. Bien sûre, il faut soustraire une colonne si on veut savoir le nombre des caractéristiques (sans les classes de sortie).

print data.shape

Classifieur naïf bayésien multinomial

Consulter le fichier codes/bayes/classer.py

On va lire le fichier en utilisant l’outil pandas

data = pandas.read_csv("../../data/champignons.csv")

Avant d’utiliser le classifieur naïf bayésien de scikit-learn, on doit transformer les catégories de chaque caractéristique en valeurs numériques. Ceci est possible en utilisant un encodeur des étiquettes (LabelEncoder)

from sklearn.preprocessing import LabelEncoder
encodeur = LabelEncoder()
for col in data.columns:
    data[col] = encodeur.fit_transform(data[col])

On sépare les données en: entrées (les caractéristiques) et sorties (les classes: comestible ou toxique). Dans notre fichier, les classes (qui sont le résultat attendu) sont dans la colonne 0, et les autres caractéristiques (les entrées) sont dans les colonnes restantes.

X = data.iloc[:,1:23] #les caractéristiques
y = data.iloc[:, 0]  #les résulats (classes)

Ensuite, il faut séparer les données en deux partie: une pour l’entrainement (on prend 80%) et une pour le test (on prend 20%). On va utiliser train_test_split de scikit-learn.

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

Toutes les caractéristiques sont nominales, donc on va utiliser MultinomialNB. il peut avoir comme parametres:

from sklearn.naive_bayes import MultinomialNB
modele = MultinomialNB()
modele.fit(X_train, y_train)

Pour prédir les classes d’un ensemble d’échantillons (ici, les données de test), on utilise la méthode predict.

y_pred = modele.predict(X_test)

Enfin, on teste la précision de notre modèle.

from sklearn.metrics import accuracy_score
print "précision: ", accuracy_score(y_test, y_pred)

Ou, on peut utiliser la méthode score qui donne le même résulat

print "précision: ", modele.score(X_test, y_test)

Sauvegarder le modèle

Après avoir entrainé un modèle, il est souhaitable de le conserver pour un usage ultérieur sans avoir besoin d’entrainer une deuxième fois. Il y a deux façons de le faire selon la doc de scikit-learn :

La deuxième est recommandée par scikit-learn. Après avoir entrainer notre modèle, on le sauvegarde.

from joblib import dump
...
modele.fit(X_train, y_train)
dump(modele, 'mon_modele.joblib')

Lorsqu’on veut prédire une classe en utilisant ce modèle, on le relance.

from joblib import load
...
modele = load('mon_modele.joblib')
y_pred2 = modele.predict(X_test2)

(Sommaire)

Bibliographie