Identifier des noms de personne dans des champs texte peut facilement devenir un défi de taille. Disons par exemple que vous effectuez une analyse des rapports de dépenses d’employés pour un de vos clients. Pour se faire, ce dernier vous remet une extraction en format CSV contenant l’information provenant de leur système informatique maison. Il vous explique qu’il s’agit d’un vieux système et qu’aucun champ n’est prévu pour y entrer le nom de l’employé. Pour palier à cette limitation du système, la comptabilité entre dans le champ description les informations suivantes:
- Nom complet de l’employé
- Numéro et nom du projet relié au rapport de dépenses
Naturellement, cette information est compilée manuellement par différentes personnes, donc le format de présentation et l’ordre dans lequel les données sont présentées varient.
Exemple:
Numéro du rapport | Description |
---|---|
2022-01 | Thomas Levasseur – P032A – Cité nord |
2022-02 | P144C – Grande roue – Micheline Lacosse |
2022-03 | Cité nord – Sonia White |
Comme nous pouvons le constater, puisque l’information est toujours présentée de façon différente, il devient très difficile de créer une requête pouvant extraire le nom des employés.
Si nous créons une fonction qui extrait les deux premiers mots du texte, ce qui fonctionnerait pour le premier rapport de dépenses, nous aurons Cité nord comme nom pour le troisième. Cela pourrait peut-être fonctionner si l’information était uniforme (nom de l’employé toujours en premier), mais encore là, nous rencontrerions un problème pour tous les noms composés de plus de deux mots (ex.: Jean Archambault Levac).
C’est ici que les expressions régulières (REGEX) viennent à la rescousse. Ces expressions permettent d’identifier, à l’aide de séquences de caractères, des modèles spécifiques dans un texte. Nous pouvons donc utiliser ces expressions pour identifier des noms, des numéros de téléphone, des numéros d’assurance sociale, etc.
Python a une librairie qui permet de facilement utiliser des expressions régulières dans nos programmes. Il s’agit de la librairie re.
Pour bien comprendre, il n’y a rien de mieux qu’un exemple.
Dans un premier temps, commençons pas importer la librairie:
import re
Maintenant, recherchons le nom dans la description du premier exemple présenté dans le tableau précédent:
var = 'Thomas Levasseur - P032A - Cité nord'
nom = re.findall(r"[A-Z][a-z]+,?\s+(?:[A-Z][a-z]*\.?\s*)?[A-Z][a-z]+", var)
print(nom)
> ['Thomas Levasseur']
Bingo ça fonctionne!
L’expression utilisée dans cet exemple en est une qui fonctionne pour la plupart des noms. Il en existe plusieurs autres dépendant des caractéristiques des noms recherches (Ex.: John Doe vs J. Doe).
Ici, j’ai utilisé la fonction findall qui permet d’identifier tous les matches contenus dans le texte soumis. Ainsi, si plusieurs noms dans le texte soumis, cette fonction permet de tous les identifier et les retourne sous forme de liste. Le module re comprend les fonctions suivantes:
Fonction | Description |
---|---|
search | Retourne de l’information sur le premier résultat identifié (position dans le texte, correspondance). |
split | Retourne dans une liste le texte brisé à chaque endroit où un résultat à été identifié. |
sub | Remplace les résultats par un texte spécifié. |
findall | Identifie tous les résultats et retourne ces derniers sous forme de liste. |
Pour nos besoins ici, c’est la fonction findall que nous utilisons.
Ajoutons un second nom dans notre texte, et voyons le résultat:
var = 'Thomas Levasseur - P032A - Cité nord Jing Xan'
nom = re.findall(r"[A-Z][a-z]+,?\s+(?:[A-Z][a-z]*\.?\s*)?[A-Z][a-z]+", var)
print(nom)
> ['Thomas Levasseur', 'Jing Xan']
Fantastique!
Maintenant, disons que vous désirez itérer chaque ligne de l’extraction que votre client vous a envoyée et créer une nouvelle colonne dans laquelle le nom de l’employé extrait sera inscrit. Voici comment vous pourriez procéder à l’aide des librairies Pandas et re.
# Importation des librairies
import pandas as pd
import re
# Création d'un DataFrame avec les données de l'exemple présenté
dataset = [['2022-01','Thomas Levasseur - P032A - Cité nord'],\
['2022-02','P144C - Grande roue - Micheline Lacosse'],\
['2022-03','Cité nord - Sonia Rousseau']]
col = ['numero_rapport','description']
df = pd.DataFrame(dataset, columns=col)
# Itération de chacun des enregistrements (lignes) du DataFrame
# Identification du nom contenu dans la colonne "description" et
# enregistrement du résultat dans une nouvelle colonne (employe)
for idx, row in df.iterrows():
var = row['description']
nom = re.findall(r"[A-Z][a-z]+,?\s+(?:[A-Z][a-z]*\.?\s*)?[A-Z][a-z]+", var)
df.at[idx, 'employe'] = nom[0]
Le résultat, sous forme de tableau (DataFrame), est le suivant:
numero_rapport | description | employe |
---|---|---|
2022-01 | Thomas Levasseur – P032A – Cité nord | Thomas Levasseur |
2022-02 | P144C – Grande roue – Micheline Lacosse | Micheline Lacosse |
2022-03 | Cité nord – Sonia White | Sonia White |