Application 1: classification automatique de textes

Cette application illustrera certains apports des outils du NLP pour la codification automatique des déclarations d’activité dans la nomenclature des activités françaises. On pourra coder dans un notebook au sein de l’environnement SSP Cloud suivant:

Onyxia

Onyxia

Ce tutoriel n’a pas vocation à introduire aux principaux concepts du NLP (tokenisation, sac de mot, embedding, etc.) mais à être une introduction pratique à la thématique de la classification textuelle. Pour découvrir les concepts centraux du NLP, se référer au cours de Python pour la data science de l’ENSAE.

Exploration du jeu de données

Ce tutoriel se propose d’illustrer la problématique de la classification automatique par le biais de l’algorithme d’apprentissage supervisé FastText, développé par Meta, à partir des données issues des déclarations Sirene.

L’idée de ce tutoriel est de classer des déclarations d’entreprise dans une nomenclature générique des activités productives. Celle-ci permet de produire de nombreuses statistiques économiques sectorielles sur le tissu productif français. L’Insee ayant vocation à produire des statistiques agrégées sur de nombreuses questions, cette approche constitue l’un des principaux cas d’application du NLP pour l’Institut dans des domaines aussi divers que la classification dans une nomenclature d’activités (NAF), une nomenclature de professions (PCS), de produits (COICOP), de lieux géographiques, etc.

Comment passe-t-on d’une déclaration en langage naturel, qui fait sens pour un entrepreneur, à une représentation plus générique, et forcément plus simpliste, de l’activité d’une entreprise, qui fait sens à une institution statistique et espérons, pour le débat public ? Grâce à des algorithmes de classement ad hoc qui permettent d’extraire une information à partir de libellés textuels. Historiquement l’Insee utilisait des règles déterministes de classement à partir d’un algorithme nommé Sicore, une IA symbolique qui classait à partir de règles métiers préconfigurée.

Avec l’avènement du machine learning, la possibilité d’entraîner un algorithme apprenant par induction plutôt que de manière déductive, est apparue être une voie d’investissement intéressante pour l’Insee. L’objet de ce TD est d’illustrer la démarche adoptée avec cette approche à partir d’un modèle un peu plus simple que celui mis en oeuvre à l’Insee mais reprenant les principales caractéristiques de celui-ci.

Le code pour lire les données est directement fourni:

import matplotlib.pyplot as plt
import pandas as pd
from wordcloud import WordCloud

DATA_PATH = "https://minio.lab.sspcloud.fr/projet-formation/diffusion/mlops/data/firm_activity_data.parquet"
NAF_PATH = "https://minio.lab.sspcloud.fr/projet-formation/nouvelles-sources/data/naf2008_liste_n5.xls"
naf = pd.read_excel(NAF_PATH, skiprows = 2)
naf['Code'] = naf['Code'].str.replace(".","")
train = pd.read_parquet(DATA_PATH)
train = train.merge(naf, left_on = "nace", right_on = "Code")
train.head(5)
nace text Code Libellé
0 8220Z MISSIONS PONCTUELLES A L AIDE D UNE PLATEFORME 8220Z Activités de centres d'appels
1 8553Z INSPECTEUR AUTOMOBILE 8553Z Enseignement de la conduite
2 5520Z LA LOCATION TOURISTIQUE DE LOGEMENTS INSOLITES... 5520Z Hébergement touristique et autre hébergement d...
3 4791A COMMERCE DE TOUT ARTICLES ET PRODUITS MARCHAND... 4791A Vente à distance sur catalogue général
4 9499Z REGROUPEMENT RETRAITE 9499Z Autres organisations fonctionnant par adhésion...

Le premier exercice a vocation à illustrer la manière classique de rentrer dans un corpus de données textuelles. La démarche n’est pas particulièrement originale mais permet d’illustrer les enjeux du nettoyage de texte.

Exercice 1

  1. Lancer le code ci-dessous pour préparer votre environnement de travail :
import spacy
!python -m spacy download fr_core_news_sm
import nltk
nltk.download('punkt_tab')
nltk.download('stopwords')
  1. Créer une fonction pour compter le nombre de textes contenant une séquence de caractères donnée dans le corpus. La tester avec “data science” et “boulanger”.

  2. Faire une fonction pour afficher le wordcloud de notre corpus dans son ensemble et de certaines catégories pour comprendre la nature de notre corpus.

  3. Retirer les stopwords à partir de la liste des mots disponibles dans SpaCy.

Aide
from nltk.tokenize import word_tokenize
import spacy

nlp = spacy.load("fr_core_news_sm")
stop_words = #liste de stopwords

# Function to remove stopwords
def remove_stopwords(text):
    word_tokens = word_tokenize(text)
    filtered_text = [word for word in word_tokens if word.lower() not in stop_words]
    return ' '.join(filtered_text)

def remove_single_letters(text):
    word_tokens = word_tokenize(text)
    filtered_text = [word for word in word_tokens if len(word) > 1]
    return ' '.join(filtered_text)

# Apply the function to the 'text' column
train['text_clean'] = (train['text']
    .apply(remove_stopwords)
    .apply(remove_single_letters)
)
  1. Refaire quelques uns des nuages de mots et étudier la différence avant nettoyage.

Dans une démarche exploratoire, le plus simple est de commencer par compter les mots de manière indépendante (approche sac de mot). Par exemple, de manière naturelle, nous avons beaucoup plus de déclarations liées à la boulangerie que liées à la data science:

filter_train_data(train, "data science").head(5)
filter_train_data(train, "boulanger").head(5)
Nombre d'occurrences de la séquence 'data science': 54
Nombre d'occurrences de la séquence 'boulanger': 1928
nace text Code Libellé
90 1071C BOULANGERIE PATISSERIE VIENNOISERIE 1071C Boulangerie et boulangerie-pâtisserie
107 1071C BOULANGERIE PATISSERIE FABRICATION 1071C Boulangerie et boulangerie-pâtisserie
153 1071C BOULANGERIE PATISSERIE GLACES CONFISERIES BOIS... 1071C Boulangerie et boulangerie-pâtisserie
314 1071C BOULANGERIE PATISSERIE VIENNOISERIE CONFISE... 1071C Boulangerie et boulangerie-pâtisserie
487 1071C BOULANGERIE PATISSERIE ACHAT VENTE ET MAINT... 1071C Boulangerie et boulangerie-pâtisserie

Les wordclouds peuvent servir à rapidement visualiser la structure d’un corpus. On voit ici que notre corpus est très bruité car nous n’avons pas nettoyé celui-ci:

Pour commencer à se faire une idée sur les spécificités des catégories, on peut représenter le corpus de certaines d’entre elles ? Arrivez-vous à inférer la catégorie de la NAF en question ? Si oui, vous utilisez sans doute des heuristiques proches de celles que nous allons mettre en oeuvre dans notre algorithme de classification.

Néanmoins, à ce stade, les données sont encore très bruitées. La première étape classique est de retirer les stop words et éventuellement des termes spécifiques à notre corpus. Par exemple, pour des données de caisse, on retirera les bruits, les abréviations, etc. qui peuvent bruiter notre corpus.

Premier algorithme d’apprentissage supervisé

Nous avons nettoyé nos données. Cela devrait améliorer la pertinence de nos modèles en réduisant le ratio signal/bruit. Nous allons généraliser notre nettoyage de texte en appliquant un peu plus d’étapes que précédemment. Nous allons notamment raciniser nos mots.

Pour cela, récupérer les fichiers suivants:

et mettre ceux-ci dans le même dossier que votre notebook Jupyter.

Le code de nettoyage est directement fourni:

from processor import Preprocessor
preprocessor = Preprocessor()

# Preprocess data before training and testing
TEXT_FEATURE = "text"
Y = "nace"

df = preprocessor.clean_text(train, TEXT_FEATURE).drop('text_clean', axis = "columns")
df.head(2)
nace text Code Libellé
0 8220Z mission ponctuel aid plateform 8220Z Activités de centres d'appels
1 8553Z inspecteur automobil 8553Z Enseignement de la conduite

Nous allons commencer à entraîner un modèle dont le plongement de mot est de faible dimension. Voici les paramètres qui seront utiles pour le prochain exercice.

import pathlib

params = {
    "dim": 25,
    "label_prefix": "__label__"
}

data_path = pathlib.Path("./data")
data_path.mkdir(parents=True, exist_ok=True)

def write_training_data(df, params, training_data_path=None):
    warnings.filterwarnings("ignore", "Setuptools is replacing distutils.")
    if training_data_path is None:
        training_data_path = get_root_path() / "data/training_data.txt"

    with open(training_data_path, "w", encoding="utf-8") as file:
        for _, item in df.iterrows():
            formatted_item = f"{params['label_prefix']}{item[Y]} {item[TEXT_FEATURE]}"
            file.write(f"{formatted_item}\n")
    return training_data_path.as_posix()
  1. Découper notre échantillon complet en train et test.
  2. FastText effectue son entraînement à partir d’objets stockés dans un .txt. Utiliser la fonction write_training_data de la manière suivante pour l’écrire.
# Write training data in a .txt file (fasttext-specific)
training_data_path = write_training_data(df_train, params, pathlib.Path(str(data_path.absolute()) + "/training_data.txt"))
  1. Avec l’aide de la documentation de la librairie FastText, entraîner votre modèle de classification.

  2. Sauvegarder le modèle sous forme de binaire, cela pourra éventuellement servir ultérieurement.

  3. Renvoyer les trois catégories les plus probables pour les nouveaux libellés suivants:

list_libs = ["vendeur d'huitres", "boulanger"]
  1. Sur l’ensemble du jeu de test, renvoyer la meilleure prédiction pour chaque descriptif d’activités. Evaluer la performance globale et la performance classe par classe, par exemple en calculant le rappel (pour les classes de plus de 200 cas).

Pour aller plus loin, introduction au MLOps

On utilise dans cette application un modèle de Machine Learning (ML) pour prédire l’activité des entreprises à partir de texte descriptifs. Les méthodes de ML sont quasiment indispensables pour traiter du texte, mais utiliser des modèles de ML pour servir des cas d’usage réels demande de respecter un certain nombre de bonnes pratiques pour que tout se passe convenablement, en particulier:

  • Tracking propre des expérimentations
  • Versioning des modèles, en même temps que des données et du code correspondants
  • Mise à disposition efficace du modèle aux utilisateurs
  • Monitoring de l’activité du modèle servi
  • Réentraînement du modèle

Une introduction à ces bonnes pratiques, auxquelles on fait régulièrement référence à travers le terme MLOps, est donné dans cette formation (dépôt associé).