From c0fb1b7d620a6c401dba6eeaee8259d288bcec2a Mon Sep 17 00:00:00 2001 From: 7404ea6678ce6fbf3a726e36f2bf2079 <7404ea6678ce6fbf3a726e36f2bf2079@app-learninglab.inria.fr> Date: Tue, 1 Oct 2024 16:19:58 +0000 Subject: [PATCH] Add work on parsing through regexp initialization --- module3/exo3/exercice_fr.ipynb | 212 ++++++++++++++++++++++++++++++++- 1 file changed, 207 insertions(+), 5 deletions(-) diff --git a/module3/exo3/exercice_fr.ipynb b/module3/exo3/exercice_fr.ipynb index 9b7cf9f..b4956d2 100644 --- a/module3/exo3/exercice_fr.ipynb +++ b/module3/exo3/exercice_fr.ipynb @@ -30,13 +30,20 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "data_url = \"http://dramacode.github.io/markdown/moliere_avare.txt\"" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "On va s'assurer qu'un fichier texte en local au format markdown contienne la pièce. Si le fichier \"moliere_avare.md\" existe on considère que c'est bon et s'il n'existe pas nous allons télécharger le contenu disponible à l'URL renseignée ci-dessus et l'écrire dans ce fichier local \"moliere_avare.md\". " + ] + }, { "cell_type": "code", "execution_count": null, @@ -57,11 +64,202 @@ " response = requests.get(data_url)\n", " # Ecriture des données téléchargées dans le fichier local\n", " with open(local_filename, \"wb\") as f:\n", - " f.write(response.content)\n", + " f.write(response.content)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Maintenant que nous sommes assurés d'avoir un fichier en local contenant le texte de l'Avare dont on va faire l'analyse, on va donc l'ouvrir, parcourir son contenu et le traiter au fur et à mesure.\n", + "\n", + "Ce que l'on sait déjà c'est que l'on va devoir créer une structure de données pour l'analyse.\n", + "On va passer par la bibliothèque Pandas et la création d'un dataframe, permettant de différencier les différents personnages et de qualifier leur \"activité\" au travers des différents actes et scènes. Néanmoins, après avoir parcouru le web, il est recommandé de passer par une structure intermédiaire pour la création du dataframe pandas. Nous allons choisir la structure de données native de python des dictionnaires en tant que structure de données intermédiaire. \n", + "\n", + "Il y a plusieurs choses auxquelles il est déjà nécessaire de penser vis-à-vis de la problématique posée et des représentations graphiques demandées, notamment celle relative à la question facultative.\n", + "\n", + "Pour commencer, afin d'obtenir une bonne lisibilité des graphiques, il sera intéressant d'associer à chaque personnage une couleur différente.\n", + "\n", + "Ensuite, la question facultative demande de déterminer à qui s'adresse chaque réplique afin d'avoir le graphe directionnel des interactions entre les personnages de la pièce. La structure de données devra donc permettre de savoir pour chaque réplique l'auteur mais aussi le destinataire de cette dernière. Ce sont des informations assez simples à obtenir mais à prendre en compte dans la manière de \"parser\" le fichier texte." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# On va d'ores et déjà utiliser une instruction afin que les graphiques s'affichent directement au sein du notebook\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "# On déclare l'utilisation de la bibliothèque pandas et on crée également le dictionnaire\n", + "# qui va nous servir d'intermédiaire avant la création du dataframe pandas\n", + "import pandas as pd\n", + "# Le dictionnaire établi une structure en tableau à 5 colonnes permettant d'enregistrer\n", + "# l'auteur, le destinataire, l'acte, la scène, ainsi que la longueur en termes de mots \n", + "# pour chaque réplique de la pièce\n", + "avareAnalysisDict = {'author':[],'recipient':[],'act':[],'scene':[],'speech_lenght':[]}\n", + "\n", + "# Nous créons également d'ores et déjà un dictionnaire des personnages de la scène\n", + "# permettant d'enregistrer les informations de liens avec les autres personnages\n", + "# de définir une couleur de représentation.\n", + "\n", + "# Ce dictionnaire est initialisé vide car il sera rempli en utilisant le nom de chaque personnage\n", + "# comme clés associées à des valeurs qui seront des dictionnaires à deux entrées\n", + "# 'links' donnant les liens avec les autres personnages sous la forme d'une liste\n", + "# 'color' permettant de régler une couleur de représentation\n", + "avarePersoDict = {}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Afin de parser le fichier en s'appuyant notamment sur les symboles de titres utilisés par le format Markdown,\n", + "il nous faut avoir recours à l'utilisation d'un outil d'analyse des expressions régulières (cf. [Wikipedia_Expression_régulière](https://fr.wikipedia.org/wiki/Expression_r%C3%A9guli%C3%A8re)). La bibliothèque\n", + "[re](https://docs.python.org/3/library/re.html) disponible nativement dans python permet de faire ce travail. " + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "import re" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'ACTEURS.'" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Chaîne de caractère indiquant le début d'analyse et de récupération des personnages\n", + "persoCaptureSTartLine = \"# ACTEURS.\"\n", + "# L'expression régulière suivante permet de valider qu'une chaîne de caractère\n", + "# contenue dans une ligne lue correspond à la ligne précédant la définition\n", + "# de la liste des personnages\n", + "m = re.search('(?<=# )ACTEURS\\.$', persoCaptureSTartLine)\n", + "m.group(0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "En effet, le résultats obtenus n'est pas un objet null, valeur None python" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\"Harpagon, Père de Cléante et d'Élise, et Amoureux de Mariane\"" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Exemple d'une ligne de la liste des personnages\n", + "persoLineExample = \" – Harpagon, Père de Cléante et d'Élise, et Amoureux de Mariane.\"\n", + "# L'expression régulière proposée est la suivante\n", + "# On cherche une chaîne de caractères Commencant par une majuscule --> [A-ZÀ-Ÿ]{1}\n", + "# potentiellement accentuée et ensuite composées de lettres potentiellement\n", + "# accentuées elles aussi, contenant des espaces, des virgules, des apostrophes --> [a-zA-ZÀ-ÿ\\s,\\']+\n", + "# et précédée d'un espace suivi d'un tiret suivi d'un espace (ce n'est pas le tiret du 6) --> (?<=\\s–\\s)\n", + "m1 = re.search('(?<=\\s–\\s)[A-ZÀ-Ÿ]{1}[a-zA-ZÀ-ÿ\\s,\\']+',persoLineExample)\n", + "m1.group(0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Voici un lien vers un site de test en ligne d'expressions régulières python \\([regexp_test](https://pythex.org/)\\) qui a aidé à mettre en place l'expression régulière précédente." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'author': [], 'recipient': [], 'act': [], 'scene': [], 'speech_lenght': []}" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def fill_perso_dict(fileToAnalyse, emptyPersoDict):\n", + " currentLine = fileToAnalyse.readline()\n", + " isStartPersoListLine = False\n", + " while (currentLine and not isStartPersoListLine):\n", + " m = re.search('(?<=# )ACTEURS\\.$', currentLine)\n", + " if m is not None:\n", + " isStartPersoListLine = True\n", + " currentLine = fileToAnalyse.readline()\n", " \n", + " # La lecture s'est arrêtée car la ligne de début de définition\n", + " # de la liste des personnages a été rencontrée.\n", + " # Nous avons néanmoins lue la ligne suivante.\n", + " # Nous devons maintenant lire ligne par ligne,\n", + " # la liste des personnages au format suivant:\n", + " # \"- NomPersonnage, lien, lien, ...\"\n", + " # Ainsi dès que la ligne ne commence plus par un tiret\n", + " # nous pouvons arrêter la lecture et le remplissage\n", + " # du dictionnaire.\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ "# On ouvre le fichier local en lecture 'r' pour en faire l'analyse\n", - "avare_file = open(local_filename,'r')\n", - "print(avare_file)" + "# en utilisant l'instruction with qui se chargera de fermer\n", + "# le fichier une fois sortie de l'instruction.\n", + "# (pas d'erreur possible par oubli d'appel à l'instruction close)\n", + "# Un rapide coup d'oeil au fichier texte nous montre une organisation\n", + "# , des symboles en début de ligne etc, que l'on va utiliser pour \"parser\"\n", + "# le fichier, à savoir le lire de manière à ranger les données\n", + "# de manière intelligente dans une structure de données facilitant\n", + "# la manipulation et l'analyse. \n", + "with open(local_filename,'r') as avare_file:\n", + " # On va commencer par parser le fichier afin de définir des couleurs pour chaque personnage\n", + " pass" ] }, { @@ -69,7 +267,11 @@ "metadata": {}, "source": [ "Notes pour plus tard: lien stack overflow vers code de customisation de graphes de la bibliothèque python networkx\n", - "https://stackoverflow.com/questions/25639169/networkx-change-color-width-according-to-edge-attributes-inconsistent-result" + "https://stackoverflow.com/questions/25639169/networkx-change-color-width-according-to-edge-attributes-inconsistent-result\n", + "lien github vers morceau de code ajoutant de la couleur et le réglage de l'épaisseur des arêtes sur un graphe\n", + "https://gist.github.com/AruniRC/2c53fe7680eeb578593ec816bbfb1653\n", + "Lien vers une page donnant un exemple d'affichage par ensemble de barres\n", + "https://www.geeksforgeeks.org/stacked-percentage-bar-plot-in-matplotlib/" ] } ], -- 2.18.1