Lors de l’article précédent, j’ai expliqué le principe de fonctionnement du Naive Bayes Classifier. Ce dernier est un algorithme de Machine Learning particulièrement prisé pour l’analyse et la classification de texte. Durant cet article, on mettra en place un « SPAM Filter » en utilisant le Naive Bayes Classifier. Notre classifieur se basera sur Python et sa librairie de Machine Learning : « Sickit Learn ».
L’algorithme prendra en entrée un e-mail et nous indiquera s’il s’agit d’un mail ou non.
C’est parti !
Présentation des données
Naï
Naive Bayes est un algorithme d’apprentissage supervisé. De ce fait, Il faudra qu’on lui fournisse une base de données d’apprentissage supervisé.
Notre jeu d’apprentissage sera une collection de mails. Pour chacun d’eux, on indiquera s’il s’agit d’un ou non.
Données d’entrée | Label |
1er mail | Spam |
2eme mail | Non Spam |
3eme mail | Non Spam |
… | … |
Notre Training Set est composé de :
- 500 mails Spam
- 2500 mails Non spam (Ham)
Chargement des données
Tout d’abord, on chargera nos mails en utilisant les modules « OS » et « IO » de Python. Voici le snippet de code de lecture et chargement des mails :
#quelques variables globales utiles PATH_TO_HAM_DIR = "D:\DEV\PYTHON_PROGRAMMING\emails\ham" PATH_TO_SPAM_DIR = "D:\DEV\PYTHON_PROGRAMMING\emails\spam" SPAM_TYPE = "SPAM" HAM_TYPE = "HAM" #les tableaux X et Y seront ordonnés et de la même taille # X représente l'input Data (ici les mails) X = [] #indique s'il s'agit d'un mail ou non Y = [] #les etiquettes (labels) pour le training set def readFilesFromDirectory(path, classification): os.chdir(path) files_name = os.listdir(path) for current_file in files_name: message = extract_mail_body(current_file) X.append(message) Y.append(classification) def extract_mail_body(file_name_str): inBody = False lines = [] file_descriptor = io.open(file_name_str,'r', encoding='latin1') for line in file_descriptor: if inBody: lines.append(line) elif line == '\n': inBody = True message = '\n'.join(lines) file_descriptor.close() return message readFilesFromDirectory(PATH_TO_HAM_DIR, HAM_TYPE) readFilesFromDirectory(PATH_TO_SPAM_DIR, SPAM_TYPE)
A l’exécution de ce code, on chargera 3000 mails (ce qui constitue notre Training Set).
- Pensez à modifier le chemin vers le répertoire contenant les mails lors de l’exécution du script sur votre machine.
Préparation du classifieur Naïve Bayes
Lors de l’article sur le fonctionnement du Naïve Bayes, j’ai illustré comment opère cet algorithme en classifiant des fruits en fonction de leurs caractéristiques. On calculait une probabilité conditionnelle pour savoir s’il s’agissait d’une banane, d’une orange ou un autre fruit. La probabilité conditionnelle était calculée en se basant sur la cardinalité/proportion de chaque caractéristique du fruit dans notre jeu de données.
Pour la classification de mails en SPAM/Non Spam, c’est la même logique qui s’applique. En effet, les mails SPAM contiennent généralement une proportion élevée de mots comme « Gagner, Gratuit,…etc » alors que dans un mail normal, ce ne sera pas le cas.
Pour classifier nos emails avec Naïve Bayes, on calcule le nombre d’occurrence des mots dans chaque mail
On doit, pour chaque mail, comptabiliser le nombre d’occurrence des mots. Cela permettra de calculer la probabilité conditionnelle comme dans l’exemple de classification des fruits.
Python nous simplifie la vie en nous proposant une fonction qui effectue ce calcul. Il s’agit de la méthode fit_transform de la classe countVectorizer.
vectorizer = CountVectorizer() counts = vectorizer.fit_transform(training_set['X'].values)
La variable counts contiendra une matrix contenant, pour chaque document, le nombre d’occurences de chaque mots
Entrainement du Naive Bayes Classifier
Tous les ingrédients sont là, il nous reste qu’a entraîner notre filtre anti-spam. Pour ce faire, on lui filera les mails 3000 mails qu’on a chargé auparavant. Pour chaque mail que le classifieur lira, on lui indiquera s’il s’agit de SPAM ou non.
Sickit_learn nous propose la classe MultinomialNB (NB pour Naïve Bayes), qui fera tous le travail pour nous.
classifier = MultinomialNB() targets = training_set['Y'].values classifier.fit(counts, targets)
Note :
- Pour être plus précis, on donne à MultinomialNB() la version « codifiée » des mails qu’on a calculé avec CountVectorizer
- Pour chaque mail, on spécifie s’il s’agit de SPAM ou non (voir l’appel classifier.fit(counts, targets))
Et voilà ! 😉
Tester le Spam Filter
Il nous reste plus qu’à tester notre filtre anti-spam. Certes, il n’est pas de la tremple que celui de Google, mais, regardons ce qu’il a dans le ventre. 🙂
- Vu que les mails de notre Training Set sont en anglais, on lui donnera des mails en anglais à classifier.
examples = ['Free Viagra now!!!', "Hi Bob, how about a game of golf tomorrow?"] example_counts = vectorizer.transform(examples) predictions = classifier.predict(example_counts)
Nos deux mails sont assez court, le premier est « Free Viagra now !!! » et l’autre est : « Hi Bob, how about…. ».
Notre filtre anti-SPAM classifie le premier comme étant un SPAM et le deuxième comme étant non-SPAM.
>> Téléchargez le code source depuis mon espace Github <<
Piste d’améliorations
Le Spam Filter qu’on vient d’implémenter est assez rudimentaire. En effet, par défaut, countVectorizer comptabilise les occurrences de chaque mots. Par ailleurs, les mots « Apple » et « Apples » peuvent être considérés différents. La même histoire pour le respect de la casse (par exemple GRATUIT et gratuit).
Pour mieux optimiser l’algorithme, on peut appliquer quelques techniques de Text Analysis. La documentation de Python en explique le principe avec un des exemples illustratifs.
Conclusion
Vous venez d’implémenter votre premier Spam Filter. Tentez d’entraîner ce filtre sur vos mails Français et partagez vos retrouvailles en commentaire 😉
Ping : Naive Bayes Classifier pour la Classification en Machine Learning
Thank you for thiis informative read, I have shared
it on Twitter.
Thank you for the share 🙂