Boîtes À Outils

Projet encadré - M1 Traitement Automatique des Langues

Ce site présente les différents outils développés pour ce projet, qui visait à traiter automatiquement des fils RSS du journal Le Monde. Ce travail a été produit dans le cadre du cours de projet encadré, donné par Serge Fleury et Pierre Magistry au second semestre du master 1 pluriTAL.

Objectifs et ressources

L'objectif de ce projet était de mettre en place une chaîne de traitement de nos données textuelles. La première étape consistait à parcourir notre arborescence de fils RSS pour en extraire les titres et les descriptions des articles du journal Le Monde. Ensuite, nous avons effectué un étiquetage des données en morpho-syntaxe et en dépendances avec les outils UDpipe et TreeTagger. Dans un troisième temps, nous avons extrait des patrons ainsi que des dépendances sur les données étiquetées. Enfin, nous avons produit un graphe permettant de visualiser et d'explorer nos données en fonction des relations de dépendances.

Pour chaque boîte à outils, il existe une version Perl et une version Python. En effet, le but de ce travail était double : nous former à la programmation en Perl et en Python tout en mettant en place une chaîne de traitement des données linguistiques.

D'autres méthodes ont été mises en place pour la réalisation de ce projet puisque nous avons choisi de travailler sur des données structurées avec le format XML. Nous avons donc utilisé les feuilles de style XSLT, les requêtes XQuery et les expressions XPath.

Les scripts, feuilles de style et requêtes disponibles au téléchargement sont commentés.


Corpus

Notre corpus se compose de fils RSS de l'année 2021 provenant du journal Le Monde et extraits chaque jour à 19h.

Un fil RSS se définit comme un format de fichier particulier dont le contenu est produit automatiquement en fonction des mises à jour d'un site, ici Le Monde. On y retrouve le titre des articles, des liens et les descriptions. Il est possible d'importer le contenu des fils RSS sur sa propre page web afin de suivre les mises à jour des informations qui nous intéressent. Notre corpus de travail se présente donc comme une arborescence de dossiers dans laquelle nous avons navigué pour extraire les contenus textuels des fichiers XML.

L'archive contenant les fils RSS de l'année 2021 du journal Le Monde est disponible ICI

Nous avons choisi de nous focaliser sur certaines rubriques pour présenter les résultats sur ce site.

Les rubriques choisies sont : À la une, international, culture et planète.


Nom Numéro
A la une 3208
International 3210
Culture 3246
Planète 3244

BAO 1 - Extraction du contenu textuel

Perl / Python - les expressions régulières

Notre démarche

Cette première étape consistait en l'extraction des titres et des description de tous les fichiers XML qui correspondent à nos rubriques. Nous avons donc écrit deux scripts, l'un en Perl, l'autre en Python. Dans les deux scripts, nous parcourons l'arborescence de notre dossier de travail à l'aide de la récursivité afin de récupérer tous les fichiers qui nous intéressent. Nous repérons ensuite le contenu textuel pertinent avec la méthode des expressions régulières et nous créons deux fichiers de sortie, l'un en XML, l'autre en TXT. Les deux scripts produisent des sorties équivalentes même si les données ne sont pas triées de la même manière.

Le script python peut être utilisé de deux manières différentes. Il peut extraire le contenu d'un seul fil (utile pour constater le nettoyage des données à effectuer ou pour de simples vérifications) mais il peut aussi extraire, comme mentionné plus haut, le contenu textuel contenu dans chaque fichier XML de notre arborescence.

Dans ces deux scripts, nous avons créé une étape de nettoyage (procédure en Perl / fonction en Python). Ce nettoyage nous a permis de retirer les éléments gênants comme l'élément CDATA ou encore de remplacer les entités de caractère comme l'esperluette. Nous avons également normalisé la ponctuation puisqu'il existait différents guillemets et différentes apostrophes. Nous avons supprimé les doublons pour chaque rubrique et dans les deux scripts par l'utilisation d'ensembles et de dictionnaires.

Les scripts présentés plus bas sont commentés et disponibles au téléchargement. Chaque étape du script est expliquée.


Scripts et fichiers de sortie

Les scripts :

Langage Téléchargement
Perl
Python -- parcours
Python -- un fil

Les fichiers de sortie :

Fichier Sortie Rubrique Téléchargement
XML Perl 3208
TXT Perl 3208
XML Python 3208
TXT Python 3208
XML Perl 3210
TXT Perl 3210
XML Python 3210
TXT Python 3210
XML Perl 3246
TXT Perl 3246
XML Python 3246
TXT Python 3246
XML Perl 3244
TXT Perl 3244
XML Python 3244
TXT Python 3244
XML Python Un fil
TXT Python Un fil

Résultats

Nous avons pu comparer les temps d'execution des programmes avec l'ajout de "time" lorsque la commande est entrée dans le terminal. Le temps d'execution des programmes en Perl et en Python est similaire même si Python semble un peu plus rapide (en moyenne : 0m0.940s real pour Perl -- 0m0.450s real pour Python).

Le nombre d'items traités est identique entre les programmes. Les résultats sont équivalents, si ce n'est le tri des données qui constitue la seule différence dans les fichiers de sortie entre les programmes.

En sortie des programmes, nous avons donc obtenu un fichier XML et un fichier TXT pour chaque rubrique. Chaque fichier de sortie contient les titres et les descriptions extraits des fils RSS de base.


BAO 2 - Etiquetage des données

Perl / Python - les expressions régulières

Notre démarche

Le but de la BAO 2 est d'étiqueter nos données en morpho-syntaxe et en dépendance lorsque l'outil utilisé le permet. Cette boîte à outils reprend la première dans la mesure où elle permet également d'extraire les titres et descriptions des fils RSS, comme le faisait la BAO 1. Nous avons ajouté des fonctions et procédures permettant l'étiquetage par TreeTagger et UDpipe.

TreeTagger permet d'étiqueter les tokens pour obtenir la forme, le lemme et le POS. Un programme de tokenisation est utilisé en amont (fourni dans l'archive). UDpipe nous permet la même chose mais nous obtenons également les relations de dépendances entre les tokens.

Nous avons donc trois scripts permettant l'étiquetage. Nous en avons créé un quatrième, permettant cette fois-ci de transformer un fichier UDpipe (CoNLL) vers le format XML. Un script permettant la conversion des résultats de TreeTagger au format XML est également fourni dans l'archive correspondante. L'ensemble de ces scripts commentés est présenté plus bas. Des archives regroupant l'ensemble des fichiers et programmes utiles à l'étiquetage sont également présentées.


Scripts et fichiers de sortie

Les scripts :

Langage Téléchargement
Perl
Python -- parcours
Python -- un fil

Script modifié et fichiers pour l'étiquetage avec TreeTagger et UDpipe :

Fichier Langage Téléchargement
UDpipe to XML Perl
Archive TreeTagger /
Archive UDpipe /

Les fichiers de sortie de Perl sont présentés dans ce tableau. Nous ne présentons pas les fichiers de sortie de Python pour une question de lisibilité. Les résultats sont identiques à ceux obtenus via Perl :

Fichier Etiquetage Rubrique Téléchargement
TXT complet / 3208
XML TT 3208
XML UD 3208
CoNLL UD 3208
TXT complet / 3210
XML TT 3210
XML UD 3210
CoNLL UD 3210
TXT complet / 3246
XML TT 3246
XML UD 3246
CoNLL UD 3246
TXT complet / 3244
XML TT 3244
XML UD 3244
CoNLL UD 3244

Résultats

Les données obtenues sont similaires entre les programmes.

Des différences existent néanmoins entre les étiqueteurs. Les POS (Part-of-speech categories -- "catégories grammaticales") utilisés ne sont pas les mêmes (NOM vs NOUN, PREP vs ADP...). Les étiqueteurs ne proposent pas non plus la même segmentation pour l'étiquetage des tokens. Ainsi, lorsque TreeTagger traite le token "du" comme une préposition (PREP:det), UDpipe va le segmenter pour pouvoir étiqueter "de" comme ADP et "le" comme DET. Ce type de phénomène mêne à de nombreuses différences dans le nombre de token étiquetés en fonction de l'outil / étiqueteur utilisé.

Les fichiers étiquetés par UDpipe sont plus riches en informations que les fichiers étiquetés par TreeTagger puisque nous avons les relations de dépendances. Ils ont tendance à être plus justes que ceux de TreeTagger au niveau de l'étiquetage.

Nous remarquons une différence entre les programmes : le temps d'execution est beaucoup plus long avec Python qu'avec Perl (3m34 real pour Perl -- 9m30 real pour Python). Les traitements sont plus nombreux en Python puisque nous créons deux fichiers de résultats de plus. En effet, nous obtenons également des fichiers étiquetés par UDpipe (module spacy) au format TXT et XML. Ce ne sont pas des fichiers au format CoNLL. Nous ne disposons que des formes, lemmes et POS avec ces fichiers.

Les sorties ainsi créées et présentées ci-dessus constitueront notre base de travail pour la BAO 3.

Ces fichiers XML sont bien formés.


BAO 3 - Extraction de patrons morpho-syntaxiques et relations de dépendances

Préparation BAO 3

Normalisation des POS des fichiers étiquetés avec TreeTagger

La première étape de notre BAO 3 est la préparation des données. En effet, nous avons noté des différences dans l'étiquetage fait par les deux outils.

Ici, le but est d'harmoniser les étiquettes données pour les POS. Pour cela, nous avons créé un script Perl qui nous permet de normaliser les étiquettes des fichiers de sortie de la BAO 2 étiquetés par TreeTagger avec les étiquettes données par UDpipe. La méthode des expressions régulières est utilisée.

Nous conservons donc les étiquettes données par UDpipe pour la suite de ce projet. Pour une question de lisibilité, nous travaillons uniquement avec les sorties produites par le script Perl lors de la BAO 2. Nous travaillons sur les fichiers produits par TreeTagger en XML, Udpipe en XML et UDpipe au format CoNLL.


Script pour normaliser les étiquettes TT :

Fichier Langage Téléchargement
Normalisation POS TT vers POS UD Perl

Résultats de cette normalisation :

Fichier Rubrique Téléchargement
newPOS_TT_XML 3208
newPOS_TT_XML 3210
newPOS_TT_XML 3246
newPOS_TT_XML 3244

Extraction de patrons morpho-syntaxiques

Dans cette première partie, nous présentons trois méthodes pour effectuer une extraction de patrons morpho-syntaxiques. Un patron morpho-syntaxique est une série de POS observée dans les données. Les patrons morpho-syntaxiques nous permettront d'observer les données linguistiques sous un nouvel angle et en contexte afin de voir ce qui peut caractériser les différentes rubriques du point de vue linguistique.

Plusieurs méthodes ont été explorées pour cette première étape : Perl/Python, XSLT/XPath et XQuery.

Solution 1 : Perl / Python

Cette première solution met en oeuvre le principe des expressions régulières. Nous avons créé un script pour chaque type de fichier (TT XML, UD XML et UD CoNLL).

En entrée de chaque programme, nous retrouvons un texte étiqueté et lemmatisé par TreeTagger ou UDpipe et une liste de POS décrivant le patron comme "DET NOUN ADJ". En sortie de chaque programme, nous obtenons une liste au format TXT avec les formes des patrons trouvés. Le nom du fichier de résultats est adapté en fonction du patron demandé.

L'utilisation d'un dictionnaire en Perl et d'une liste en Python nous permet de compter les occurrences et de trier les résultats pour voir apparaître les termes les plus présents tout en haut du fichier. Nous avons également pris la décision de normaliser les formes trouvées en les passant toutes en minuscules. Ceci nous permet de regrouper des occurrences qui pourraient être identiques mais qui sont considérées différentes en raison des majuscules. La fonction ".lower()" est utilisée en Python et la fonction "lc()" est utilisée en Perl.

Puisque nous avons compté le nombre d'occurrences en Perl, nous avons créé une fonction Python nous permettant de faire la même chose. Pour cela, nous manipulons des listes afin de compter chaque élément. Nous associons donc un terme avec le comptage de sa présence dans le fichier. Puis nous créons une nouvelle liste pour y insérer les élements qui n'ont encore jamais été rencontrés (nous évitons ainsi les doublons). Nous retournons ensuite un résultat qui est la liste nouvellement créée et inversée pour permettre un affichage similaire à Perl.

Le fonctionnement global des deux programmes est le même : nous parcourons les données et si notre patron correspond aux données observées, nous pouvons extraire la forme. Nous commençons par vérifier la correspondance du premier POS du patron aux données pour éviter des calculs inutiles.

Le script Python présente une particularité : l'utilisation d'un buffer. En effet, nous ne lisons pas les données globalement. Le buffer est une fenêtre glissante qui va parcourir nos données et récupérer les formes correspondant au patron s'il y a correspondance. Nous lisons ainsi le fichier ligne par ligne.

Les sorties créées à partir des deux programmes sont donc similaires et le temps d'execution des programmes également. Cette méthode est jugée plus simple d'utilisation que les méthodes suivantes puisque nous pouvons demander n'importe quelle longueur de patron, les programmes s'adaptent. Comme nous le verrons, les feuilles de style et requêtes XQuery doivent être retravaillées pour correspondre à la longueur des patrons souhaités.


Scripts :

Fichier Langage Téléchargement
TT xml Perl
UD xml Perl
UD CoNLL Perl
TT xml Python
UD xml Python
UD CoNLL Python

Résultats :

Fichier Sortie Rubrique Patron Téléchargement
TT XML Perl 3208 ADP DET NOUN
UD XML Perl 3208 ADP DET NOUN
UD CoNLL Perl 3210 NOUN ADP NOUN ADP
UD XML Perl 3210 VERB DET NOUN
UD XML Perl 3246 NOUN ADJ
TT XML Python 3244 ADJ NOUN
UD XML Python 3244 NOUN ADV ADJ

Solution 2 : XSLT / XPATH

Cette deuxième solution met en oeuvre la méthode des feuilles de style avec XSLT et XPath. Nous traitons uniquement le patron "NOUN ADJ" dans cette partie, les feuilles de style pour d'autres patrons sont disponibles sur le site créé pour le projet de Documents Structurés. Nous travaillons sur les sorties de la BAO 2 qui sont au format XML uniquement puisque le langage XPath va nous permettre de naviguer dans les données qui sont structurées.

Pour le patron mentionné plus haut, nous avons créé des feuilles de style permettant de générer les résultats des extractions de patrons au format TXT ainsi qu'au format HTML. Nous avons également créé des feuilles de style pour les deux types de fichiers au format XML qui sont à notre disposition : le fichier TreeTagger et le fichier UDpipe.

Nous avons créé une règle qui doit être appliquée sur les noeuds "titre" et "description". Cette règle va tester le fait que l'élément contienne le premier POS du patron. Nous testons ensuite les frères suivants pour tester l'intégralité du patron. Nous récupérons ensuite la forme pour l'affichage.

Feuilles de style :

Fichier Langage Téléchargement
TT_html XSLT
UD_html XSLT
TT_txt XSLT
UD_txt XSLT

Résultats :

Fichier Rubrique Téléchargement
TT_html 3208
TT_html 3210
UD_txt 3208
UD_txt 3210

Solution 3 : XQUERY

Cette troisième solution nous permet de travailler avec les requêtes du langage XQuery. Nous travaillons sur le logiciel BaseX. Comme pour la précédente solution, nous travaillons uniquement sur les fichiers XML. Nous présentons ici la requête pour le patron "DET NOUN ADJ". Les autres requêtes avec des longueurs de patrons différentes sont présentées sur le site du projet de Documents Structurés.

Le fonctionnement est le même que pour la solution précédente. Nous testons le POS du premier élément ainsi que les POS des frères suivants. Nous assemblons ensuite les formes trouvées pour l'affichage des résultats.


Requête :

Fichier Langage Téléchargement
UD_XML XQUERY

Résultats :

Fichier Rubrique Téléchargement
UD_txt 3208
UD_txt 3210
UD_txt 3244


Extraction de relations de dépendances

Dans cette seconde partie, nous présentons trois méthodes pour effectuer une extraction de relations syntaxiques de dépendances. Une relation de dépendance est une relation entre deux tokens, l'un est le gouverneur, l'autre le dépendant. Les relations sont les liens syntaxiques entre les mots ou tokens d'une phrase. Ici, le but est de voir les relations entre les tokens étiquetés par UDpipe. Par exemple, nous pouvons observer la relation "obj" entre deux tokens. Cela nous permettra de voir les données des différentes catégories sous un nouvel angle.

Plusieurs méthodes ont été explorées pour cette seconde étape : XSLT/XPath, XQuery et Perl/Python.

Solution 1 : XSLT / XPATH

Cette première solution pour l'extraction des relations de dépendances consiste à utiliser les feuilles de style XSLT ainsi que le langage XPath. Le fonctionnement global sera le même pour les trois solutions.

Nous commençons par voir si nous retrouvons la relation dans les données. Si c'est le cas, alors on va mémoriser la forme du dépendant, la position de la tête (gouverneur) ainsi que la position du dépendant. Ensuite, en fonction de la position de la tête par rapport au dépendant, nous recherchons dans les frères précédents ou dans les frères suivants, la position de la tête pour pouvoir en extraire la forme. Cette règle s'applique sur les noeuds "titre" et "description".

Comme pour l'extraction des patrons, nous permettons une sortie en TXT ainsi qu'en HTML. Les données en entrée sont uniquement celles provenant de l'étiquetage de UDpipe puisque c'est le seul outil qui propose ce type d'étiquetage.

Cette solution nous permet de modifier simplement les relations souhaitées, directement dans la feuille de style au niveau de la déclaration de notre paramètre. Ici, nous présentons les résultats pour la relation "obj".


Feuilles de style :

Fichier Langage Téléchargement
UD_html XSLT
UD_txt XSLT

Résultats :

Fichier Rubrique Téléchargement
UD_html 3208
UD_html 3246
UD_txt 3210
UD_txt 3244

Solution 2 : XQUERY

Pour cette deuxième solution, nous utilisons le langage XQuery via le logiciel BaseX. Le fonctionnement est très similaire à la solution évoquée plus haut. Nous pouvons également facilement modifier les relations à repérer dans les données.

Pour l'affichage, nous regroupons les résultats par fréquence et en ordre décroissant.


Requête :

Fichier Langage Téléchargement
Relation XQUERY

Résultats :

Fichier Relation Rubrique Téléchargement
UD_txt obj 3208
UD_txt obj 3210
UD_txt subj 3210
UD_txt obj 3244

Solution 3 : Perl / Python

Pour cette troisième et dernière solution, nous avons utilisé la méthode des expressions régulières avec Perl et Python.

Nous avons tout d'abord homogénéisé les balises "titre" et "description" pour obtenir une seule et même balise qui est devenue le délimiteur pour la lecture des données. En effet, cette étape est cruciale dans la mesure où si nous n'avons pas de séparateur de phrases, le programme ira chercher les positions des têtes (gouverneurs) dans tout le fichier. Les résultats n'auraient alors aucun sens. Nous avons donc créé un script Perl permettant cette transformation. Les fichiers obtenus ont servi d'input aux programmes Perl et Python pour l'extraction des relations de dépendances.

Ensuite, le principe des deux programmes est le même que pour les autres solutions mentionnées. Nous utilisons un dictionnaire en Perl et une liste en Python pour compter la fréquence des couples tête-dépendant et pour pouvoir les afficher de manière décroissante. Comme pour l'extraction des patrons, nous normalisons les données en les passant toutes en minuscules.

En sortie de chaque programme, nous affichons à l'écran la liste des occurrences de la relation souhaitée avec la tête et le dépendant. Nous pouvons utiliser une commande bash afin d'écrire ce résultat dans un fichier TXT.

La commande bash utilisée est : perl bao3_extractRelation.pl preInput.xml obj > resultat_relation_obj_3208.txt


Script de transformation des balises "titre" / "description" en "p" (phrase) :

Fichier Langage Téléchargement
Transformation en phrases Perl

Scripts :

Fichier Langage Téléchargement
UD XML Perl
UD XML Python

Résultats :

Fichier Sortie Relation Rubrique Téléchargement
UD XML Perl obj 3208
UD XML Perl obj 3210
UD XML Perl subj 3244
UD XML Perl subj 3246
UD XML Python obj 3244
UD XML Python obj 3246

Résultats de la BAO 3

Les résultats obtenus sont identiques d'une solution à une autre.

Pour les extractions de patrons, les solutions les plus simples à manipuler sont les programmes Python et Perl car il est simple de modifier le patron souhaité. Les programmes s'adaptent aux longueurs des patrons. Les feuilles de style et requêtes doivent être retravaillées pour obtenir des patrons plus ou moins longs.

En ce qui concerne les extractions de relations de dépendances, toutes les solutions sont simples à mettre en oeuvre et à modifier. Les programmes Perl et Python nous donnent la fréquence d'apparition des couples tête-dépendant. Cela nous sera très utile pour la mise en oeuvre de la BAO 4 lorsque nous allons donner un poids aux données.


BAO 4 - Des textes aux graphes

Le but de cette dernière BAO est de visualiser les données extraites grâce à des graphes générés avec l'outil Padagraph. Nous allons représenter les relations de dépendances par des noeuds et des relations entre ces noeuds. Nous avons représenté les gouverneurs avec des triangles et un poids a été donné aux relations en fonction de la fréquence observée pour chaque couple tête-dépendant.

Nous repartons de notre script Python écrit pour l'extraction des dépendances. Nous ajoutons une sortie csv qui respecte la syntaxe imposée par l'outil. Nous envoyons ensuite ce fichier sur Padagraph.

La commande pour executer ce script et pour l'envoyer sur Padagraph est mentionnée dans le script commenté.


Script :

Fichier Langage Téléchargement
UD XML Python

Résultats pour la relation "obj" :

Pour la rubrique 3208 - À la Une :


Pour cette rubrique, nous constatons des occurrences intéressantes comme "accélérer vaccination", "imposer vaccination", "recevoir injection", "suspendre vaccination", "rendre hommage", "renforcer lutte". Il est à noter que les données ont été exraites tout au long de l'année 2021, année très marquée par la période de la pandémie. Il n'est pas étonnant de retrouver ce type d'occurrences dans cette rubrique. De manière générale, tous les gouverneurs de "vaccination" sont intéressants et ramènent aux enjeux rencontrés lors de la pandémie.


Nuage de mots - relations obj rubrique 3208

Nous avons également généré un nuage de mots afin d'explorer les données d'une manière plus simpliste mais tout autant visuelle. Comme nous pouvons le constater, les résultats ne sont pas informatifs et ne permettent pas de caractériser quelque rubrique que ce soit. L'idée était de comparer l'informativité de ces nuages que nous connaissons tous avec celle des graphes générés sur Padagraph. Les graphes sont bien évidemment plus informatifs comme mentionné précédemment dans la mesure où les données sont presque toutes connectées. Il est possible de rechercher des occurrences, de nous intéresser aux voisins de notre occurrence et il est très facile de naviguer dans les données.


Pour la rubrique 3210 - International :


Concernant cette rubrique, nous constatons des occurrences intéressantes comme "réactiver relation", "renouer relation", "poursuivre dialogue", "ouvrir dialogue". Cette rubrique traite des enjeux internationaux. Ces notions sont évidemment essentielles à l'international, les occurrences et relations de dépendances "obj" de "relation" et de "dialogue" sont donc intéressantes à observer dans ce contexte.


Pour la rubrique 3246 - Culture :


Pour cette rubrique, nous constatons des occurrences comme "présenter film", "attendre édition", "livrer critique", "séduire lecteur", "captiver lecteur" mais aussi "éveiller conscience". Ces occurrences représentent plutôt bien la rubrique de la culture puisque les arts sont mentionnés. Le fait d'éveiller les consciences et de livrer des critiques sur des oeuvres ou d'autres sujets est aussi l'objectif des arts en général.



Bilan du projet

Tout au long de ce projet, nous avons élargi nos compétences en programmation, tant sur Perl que sur Python. Nous avons également appris à traiter des données linguistiques, de leur extraction sur le web à leur visualisation.

Plusieurs outils ont été utilisés lors de ce projet comme les étiqueteurs avec UDpipe et TreeTagger, les feuilles de style, les requêtes XQuery. Le but de ce projet était également de pouvoir comparer ces différents outils pour nous permettre de mieux comprendre les forces et lacunes de chacun.