Implémentation d’un SPAM Filter avec Naive Bayes Classifier et Python

de | 5 août 2017

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 !

Naive Bayes classifier Spam Filter

Naive Bayes classifier Spam Filter

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 SPAM ou non.

Base de données d’apprentissage (Training Set)
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 😉

3 réflexions au sujet de « Implémentation d’un SPAM Filter avec Naive Bayes Classifier et Python »

  1. Ping : Naive Bayes Classifier pour la Classification en Machine Learning

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.