{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ " # Traitement de données en table\n", " \n", "## 4 -Fusionner des tables\n", "\n", "Il arrive que des données qui pourraient être mises en relation entre elles se trouvent stockées dans des tables distinctes. Il est alors intéressant de chercher à réaliser la fusion de ces tables.\n", "(En anglais on rencontrera le verbe : to merge = fusionner)\n", "Deux cas se présentent :\n", "\n", " • Les tables partagent les mêmes attributs ( ou descripteurs) : on fait une concaténation\n", " • Les tables ont des attributs différents (mais en ont au moins un en commun) : on fait une jointure\n", " \n", " ### 4.1 Concaténation :\n", "#### 4.1.1. Présentation visuelle\n", "\n", "On a récupéré deux tables de données donnant les départs des vols du matin et ceux de l’après-midi à partir de l’aéroport Paris Charles de Gaulle (Printemps 2020… en pleine épidémie Covid, donc très peu d’avions...et c’était la liste des vols prévus !). \n", "\n", " - vols du matin : **CDG_matin.csv**\n", " - vols après-midi : **CDG_apres_midi.csv**\n", " \n", "Ces deux tables ont des descripteurs identiques (Vol ; Compagnie ; Code_aeroport ; Départ ). On peut alors réaliser la concaténation des deux tables pour obtenir la liste des vols de la journée. Pour cela, on vient ajouter les enregistrements de la table des vols de l’après-midi à ceux de la table des vols du matin. \n", "\n", "Vu depuis un tableur, la représentation que l’on peut avoir de cette concaténation est très simple : \n", "![title](images/concatenation_tables.png)\n", "\n", "Remarque : on rappelle que dans une table de données, les valeurs d’un même attribut (ou descripteur) doivent être toutes de même type. Cela implique que ces types devaient être les mêmes dans chacune des tables avant de faire la fusion.\n", "Si les tables proviennent de sources différentes, il est impératif de s’assurer de cette homogénéité avant de réaliser la fusion.\n", "\n", "Avec un tableur, une telle opération se fait rapidement avec un copier-coller. La question à se poser (mais on doit aussi se la poser aussi quand on va faire le travail par programmation) c’est :\n", "\n", " • est-ce que je vais compléter l’une des tables avec l’autre, et si oui dans quel sens ?\n", " • ou, est-ce que je crée une troisième table, fusion des deux premières ?\n", " \n", "Remarque : on évoque ici la fusion de deux tables par concaténation, mais on peut bien sûr en fusionner davantage. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 4.1.2. Réalisation d'une concaténation avec Python\n", "\n", "Pourquoi « s’embêter » à réaliser une concaténation par programmation alors que c’est si simple avec un tableur ? \n", "\n", "→ Parce que beaucoup de traitements de fichiers se font «derrière le rideau», sans intervention d’un utilisateur. Un exemple : rafraîchir la table qui résulte de la fusion à chaque fois que l’une des tables d’origine est modifiée (par un utilisateur ou un autre processus automatique). Pour y arriver, on doit automatiser la procédure, et cela ne peut se faire que par programmation !\n", "\n", "On a vu qu’une série de données en table peut-être représentée en Python par une liste. Chaque élément de la liste représente un enregistrement de la table (Cf Vocabulaire sur les données en table), représenté lui même par une liste ou un dictionnaire.\n", "\n", "t1 = \\[ { D1 }, { D2 }, …. , { D10 }] \t(Tous les dictionnaires D1 à D10 ont les mêmes clés )\n", "\n", "t2 = \\[ { Da }, { Db }, …. , { De }] \t(Tous les dictionnaires Da à De ont les mêmes clés et bien sûr les mêmes que les dictionnaires de t1)\n", "\n", "Après la concaténation (réalisée ici en créant une troisième table t3) :\n", "\n", "t3 = \\[ { D1 }, { D2 }, …. , { D10 }, { Da }, { Db }, …. , { De }] \n", "\n", "Après tri sur critère spécifique, les deux tables fusionnées n’ont plus vocation à être l’une après l’autre et on pourrait avoir par exemple :\n", "\n", "t3 = \\[ { Da }, { D1 }, { D2 }, { Db }…. , { De }, … ,{ D10 }] \n", "\n", "\n", "Dans la cellule ci-dessous, on ouvre en lecture les deux fichiers (qui se trouvent dans un répertoire 'images' sur ce serveur) et on récupère deux objets fichier (fichier1 et fichier2).\n", "Compléter le code donné pour :\n", "\n", " - Utiliser la méthode DictReader() pour récupérer les enregistrements de chacune de ces tables.\n", " - afficher pour vérification ces deux tables de données :" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "# utilisation de csv.DictReader() :\n", "\n", "import csv\n", "\n", "fichier1 = open('data/CDG_matin.csv', 'r') # ouverture des fichiers en lecture\n", "fichier2 = open('data/CDG_apres_midi.csv', 'r') \n", "\n", "# code à compléter (ne pas oublier de fermer l'objet fichier):\n", "???\n", "...\n", "???\n", "\n", "# Affichages pour vérifier que les fichiers ont été correctement chargés :\n", "print(\"Vols du matin :\")\n", "# code à compléter pour afficher la table des vols du matin :\n", "???\n", "...\n", "???\n", "\n", "\n", "print(\"\\n Vols de l'après-midi : \")\n", "# code à compléter pour afficher la table des vols de l'après-midi :\n", "???\n", "...\n", "???\n", "\n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Créer une nouvelle structure nommée **\"vols\"** pour accueillir la concaténation des tables de vols du matin et de l'après-midi.\n", "\n", "On réalisera l'affichage complet de la structure \"vols\" pour vérifier le résultat attendu :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# code à compléter ... une ligne doit suffire ! :\n", "???\n", "#affichage de la structure 'vols' :\n", "print('Tous les vols de la journée : \\n')\n", "\n", "# à compléter pour avoir l'affichage (vérifier que la fusion a bien eu lieu)\n", "???\n", "...\n", "???" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " ### 4.2 Jointure :\n", " \n", " #### 4.2.1 Présentation :\n", " \n", "Les tables précédentes montraient pour chaque aéroport l’existence d’un code de 3 caractères : ALG, VIE, AMS …\n", "Ce code est normé au niveau international ; il est d’ailleurs affiché en gros sur les étiquettes des bagages, ce qui permet de vérifier rapidement où doit aller le bagage :\n", "\n", "![title](images/etiquettes.jpg)\n", "\n", " On a récupéré une table de données des aéroports du monde entier dont voici un tout petit extrait pour quelques aéroports français. On remarque que tous les aéroports n’ont pas ce code d’identification dans cette table (à la place ils ont un code générique de non attribution de valeur : \\N )\n", "\n", "On y retrouve les codes CDG et ORY des étiquettes ci-dessus :\n", "\n", "![title](images/aeroports.png)\n", "\n", "Les attributs de cette table de données sont : ‘Aeroport’ , ‘Code_aeroport’, ‘Ville’, ‘Pays’\n", "L’association de ces deux tables, par le biais de l’attribut commun ‘Code_aeroport’ permet de voir :\n", "\n", "![title](images/jointure.png)\n", "\n", "que le vol AF6290 de la compagnie Air France à 10:05 AM part pour l’aéroport de Belgrade en Serbie.\n", "\n", "On voit que cette association va être un peu plus technique que la simple concaténation précédente, mais qu’elle ouvre grand sur une des problématiques actuelles : le croisement des données issues des nombreuses bases de données que chaque personne alimente volontairement ou non tout au long de sa vie...\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 4.2.2. Réalisation d’une jointure en Python\n", "\n", "Cette opération de jointure ne va pas consister à venir « coller » à droite de la ligne N°5 de la table des vols, la ligne N°1687 de la table des aéroports. (Cela ne serait pas possible car on se retrouverait avec deux fois le même attribut ‘Code_aeroport’ ce qui n’est pas autorisé dans un même dictionnaire)\n", "On va créer une nouvelle table, dont les attributs seront pris dans chacune des deux tables. On pourra d’ailleurs les réorganiser dans l’ordre que l’on veut. Par exemple :\n", "\n", "![title](images/jointure_resultat.png)\n", "\n", "\n", "\n", "\n", "\n", "\n", "Remarque : on n’est pas obligé de garder l’attribut commun de jointure si cela n’a pas d’intérêt particulier. Ceci dit, comme il sert à relier les deux tables, le garder permettrait une re-vérification croisée en direction des deux tables de départ.\n", "\n", "Proposition de démarche à convertir en Python :\n", "\n", " • charger les données des fichiers dans deux listes : ‘vols’ et ‘aeroports’\n", " \n", " • Créer une nouvelle table vide : ‘vols_details’\n", " \n", " • prendre le premier enregistrement de la table de vols (nommé ci-dessous dict_vol)\n", " \n", " ◦ prendre le premier enregistrement de la table des aéroports (nommé ci-dessous dict_aero) :\n", " \n", " ▪ si le code aeroport est le même pour ces deux lignes alors :\n", " \n", " • ajouter le dictionnaire { 'Depart' : dict_vol['Depart'] , 'Vol' : dict_vol['Vol'] , \n", " 'Code_aeroport' : dict_vol['Code_aeroport'] , 'Ville' : dict_aero['Ville'] , \n", " 'Pays' : dict_aero['Pays'] , 'Compagnie' : dict_vol['Compagnie'] }\n", " \n", " • sinon passer à l’enregistrement suivant de la table aéroports et recommencer le test.\n", " \n", " ▪ on a fait la jointure pour le premier enregistrement de la table ‘vols’ passer à l’enregistrement suivant de cette table des vols et ce jusqu’à la fin de cette table\n", " \n", " \n", "On pourra faire ce travail de différentes façons :\n", "\n", " • avec deux boucles imbriquées\n", " \n", " • avec création de la liste ‘vols_details’ directement en compréhension. \n", " \n", "Remarque : on pourrait fort bien changer les noms des attributs pour cette nouvelle table créée (par exemple, remplacer :\n", " { ‘Depart’ : vols[‘Depart’] , …\n", "par\n", " { ‘Horaire’ : vols[‘Depart’] , …\n", "ce qui donnerait à l’affichage dans un tableur : \n", "\n", "![title](images/jointure_modif_attribut.png)\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# l'une des tables a déjà été construites dans une cellule précédente : 'vols'\n", "# ne pas oublier de ré-exécuter les premières cellules pour que 'vols' existe\n", "# on doit charger la table de données présente dans le fichier airports.csv présent \n", "# dans le répertoire images de ce serveur\n", "import csv\n", "fichier = open('data/airports.csv', 'r') \n", "\n", "# code à compléter (ne pas oublier de fermer l'objet fichier)\n", "???\n", "...\n", "???\n", "\n", "# code à compléter pour la création de la liste vols_details par jointure :\n", "???\n", "...\n", "???\n", "\n", "# affichage pour vérification :\n", "for elt in vols_details:\n", " print(elt)\n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Code alternatif :\n", "\n", "On peut arriver au même résultat en réalisant une création de vols_details en compréhension.\n", "Le principe reste le même : itérer sur les deux structures et construire l'enregistrement (un dictionnaire) en cas d'égalité des clé 'Code_aeroport' entre les deux enregistrements comparés :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "???\n", "...\n", "???\n", "\n", "\n", "for elt in vols_details:\n", " print(elt)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Exemple avec modification de l'attribut 'Depart' en 'Horaire' :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "???\n", "...\n", "???\n", "\n", "for elt in vols_details:\n", " print(elt)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.3" } }, "nbformat": 4, "nbformat_minor": 2 }