python fichier csv

Identification

Infoforall

18 - Introduction à l'Opendata avec Python


Opendata : en français, on dit données ouvertes. Il s'agit d'un concept : le fait que les données et l'information sont un bien commun à l'humanité et qu'il est important de pouvoir la diffuser et la partager. On trouve désormais des fichiers regroupant des données traitant de tout et de rien très facilement sur le Web.

Quelques critères permettant de qualifier une information OpenData :

  • Complète
  • Primaire
  • Opportune
  • Accessible
  • Exploitable
  • Non-discriminatoire
  • Non-propriétaire
  • Libre de droits
  • Permanente
  • Gratuite

Nous allons en parler un peu ici. Si vous voulez plus de renseignements après cette activité : article Wikipedia.

Prérequis : Dictionnaires et tableaux.

Attention : on rappelle que les tableaux qui nous utilisons dans Python sont en réalité des objets de type list. Or, justement, les listes sont une structure de données assez différentes des tableaux.

Nous utiliserons donc les lists de python comme des tableaux (arrays en anglais).

Evaluation ✎ : questions 04-06-08-09-12-18-19-20.

Logiciel nécessaire pour l'activité : Python 3 : Thonny, IDLE ...

1 - OpenData

A la fois mouvement philosophique et politique qui vise à fournir l'information au plus grand nombre et à la diffuser. Elle possède les mêmes fondements finalement qu'une notion comme la liberté de la presse. Plus l'information est libre d'accès, plus les manipulations, les mensonges et les contre-vérités seront difficiles à maintenir.

Il s'agit normalement de publier de façon légale des informations en permettant aux autres de les lire, de les publier et de les exploiter. Il existe de multiples licences liées à ces publications bien entendu.

Cette diffusion de l'information a déjà provoqué bien des remous dans le monde. Il existe une autre thématique proche de l'OpenData : la fuite de données. Celle des lanceurs d'alerte qui publient des données non libres. Ils savent qu'ils seront poursuivis et qu'ils risquent gros mais décident d'informer le monde d'une malversation ou plus généralement d'un problème. Ainsi le site Wikileaks a publié des données liées aux renseignements américains. Il ne s'agissait pas d'OpenData ici mais la diffusion de ces informations a clairement modifié le monde et la vision qu'ont les gens de la collecte d'informations.

Maintenant que la diffusion est facile et répandue reste le problème de la fiabilité : publier des données ne veut pas dire que l'information soit réelle ! Le travail des journalistes n'est pas fini. Au contraire, il ne fait que commencer et il leur faudra désormais des outils informatiques puissants pour analyser différentes sources et fournir une probabilité de véracité.

Nous retrouvons ici Tim Berners-Lee. Le créateur du Web a défini une échelle dans l'OpenData.

Photo de Tim Berners-Lee
Tim Berners-Lee (2010) - CC BY 2.0 - Paul Clarke — originally posted to Flickr
Rang Signification
Données non filtrées (éventuellement dégradées), mises en ligne avec un format non standard ou sans format du tout
★★ Données disponibles de manière structurée (données au format CSV, TSV, XML, ou issues d'un format dont la spécification est connue : PDF, fichier tableur...)
★★★ Données librement exploitables. Juridiquement (Cf. licences) et techniquement (les données ne sont pas lisibles uniquement avec un logiciel propriétaire (EXCEL ou autres).
★★★★ Données datées, identifiées par des URL (avec date de mise à jour) afin que l'on puisse « pointer » un lien vers elles (et les retrouver éventuellement mises à jour).
★★★★★ Données liées à d'autres données graçe à un ou des données communes, pour les contextualiser et les enrichir

Nous allons voir ce que signifient tous ces termes.

Données non structurées (rappel SNT)

Une donnée non structurée est une donnée présente mais qu'un système automatisé aura bien du mal à retrouver.

Exemple

C'est une voiture de sport de couleur rouge et conduite par un moustachu qui porte des chemises à fleurs.

L'un de ses amis possède un bel hélicoptère. Celui-ci est plutôt marron mais possède également quelques lignes colorées dans des tons rouge, bleu et jaune.

01° Quel est le type et la couleur du premier véhicule ? Quel est le type et la couleur du second véhicule ?

...CORRECTION...

Véhicule : Voiture de sport --- Couleur : rouge

Véhicule : Hélicoptère --- Couleur : marron

Vous venez d'utiliser un centre de traitement de l'information super performant : votre cerveau.

Ca, ce n'est pas possible pour un ordinateur. Il existe une branche de la recherche informatique qui traite de cette capacité de donner du sens à un texte brut mais c'est loin d'être facile et rapide.

La meilleur façon pour qu'un ordinateur puisse traiter cela est de lui macher le travail : nous allons structurer les données.

Données structurées (rappel SNT)

Une donnée structurée est une donnée présentée selon un format connu et fixe.

Il peut s'agir par exemple d'un tableau à deux entrées.

Exemple

Identifiant Type Utilisation Couleur
1 Voiture Sport Rouge
2 Hélicoptère Tourisme Marron
3 Voiture Sport Rouge

Les colonnes sont nommmées les descripteurs, les champs, les attributs ou les caractères selon les spécialités scientfiiques. Ici, j'utiliserai le mot attribut.

Toutes les données présentes dans ce tableau partagent les mêmes attributs et les fournissent dans le même ordre : ID - Type - Catégorie puis Couleur.

Chaque ligne (à part l'en-tête, header en anglais) se nomme un enregistrement, un objet, un individu selon la spécialité scientifique. Ici, nous parlerons d'enregistrement.

L'intersection d'un enregistrement et d'un attribut se nomme une valeur.

L'ensemble des données {enregistements et attributs} se nomme la collection en informatique ou population en mathématique.

Collection Attributs
Identifiant Type Utilisation Couleur
Enregistrements 0 Voiture Sport Rouge
1 Hélicoptère Tourisme Marron
2 Voiture Sport Rouge

02° Quels sont les attributs de la collection précédente ? Combien y-a-t-il d'enregistrements dans cette collection ? Quelle est la valeur qui correspond à l'attribut d'index 2 et à l'enregistrement d'index 0 ?

...CORRECTION...

Il y a 4 attributs :

  • Index 0 : Identifiant
  • Index 1 : Type
  • Index 2 : Utilisation
  • Index 3 : Couleur

Il y a 3 enregistrements d'index 0, 1 et 2.

La valeur d'index 2 en attribut (colonne Utilisation) et d'index 0 en enregistrement correspond à sport

03° Quel est le seul attribut qui permette de distinguer le premier et le dernier enregistrement ?

...CORRECTION...

Il s'agit de l'identifiant. On rajoute TOUJOURS un identifiant qu'on définit soi-même. De cette façon, nous sommes certains de pouvoir distinguer deur enregistrements même si les contenus sont similaires.

✎ 04° Peut-on séparer deux individus uniquement à l'aide du nom et du prénom ? A quoi sert le numéro de sécurité sociale ?

2 - Tableau de tableaux

Voyons comment gérer cela avec Python.

Nous allons créer des tableaux de tableaux ou des tableaux de dictionnaires.

Vous allez voir que c'est finalement assez intuitif.

Comme les données sont structurées, nous pourrions stocker les valeurs d'un enregistrement dans un tableau.

1 2 3
enr0 = ['0', 'voiture', 'sport', 'rouge'] enr1 = ['1', 'hélicoptère', 'tourisme', 'marron'] enr2 = ['2', 'voiture', 'sport', 'rouge']

05° Que va-t-on récupérer si on lance ceci dans le Shell Python après avoir placé les 3 variables précédentes en mémoire ?

>>> enr0[1] >>> enr1[1] >>> enr2[1]

...CORRECTION...

>>> enr0[1] 'voiture' >>> enr1[1] 'helicoptère' >>> enr2[1] 'voiture'

On récupère donc bien les valeurs stockées dans l'attribut TYPE qui correspond à l'index 1.

✎ 06° Sur le même principe que la question précédente, que doit-on taper pour récupérer la couleur de l'enregistrement 2 ?

Pour l'instant, nous avons encore 3 variables : une pour chaque enregistrement. C'est pénible.

Et si nous stockions nos enregistrements dans un tableau. On obtient ainsi un tableau de tableaux !

1 2 3 4 5
enr0 = ['0', 'voiture', 'sport', 'rouge'] enr1 = ['1', 'hélicoptère', 'tourisme', 'marron'] enr2 = ['2', 'voiture', 'sport', 'rouge'] maCollec = [enr0, enr1, enr2]

07° Que va-t-on récupérer si on lance ceci dans le Shell Python après avoir placé les 4 variables précédentes en mémoire ?

>>> maCollec[0] >>> maCollec[1] >>> maCollec[2]

...CORRECTION...

>>> maCollec[0] ['0', 'voiture', 'sport', 'rouge'] >>> maCollec[1] ['1', 'helicoptère', 'tourisme', 'marron'] >>> maCollec[2] ['2', 'voiture', 'sport', 'rouge']

On récupère donc bien les valeurs stockées dans l'attribut TYPE qui correspond à l'index 1.

Lorsqu'on utilise donc un index sur le tableau maCollec on obtient un tableau. Et si on veut lire uniquement un attribut ? Il suffit de rajouter un crochet supplémentaire !

Exemple

>>> maCollec[0] ['0', 'voiture', 'sport', 'rouge'] >>> maCollec[0][0] '0' >>> maCollec[0][1] 'voiture' >>> maCollec[0][2] 'sport'

En détails, maCollec[0][1] veut dire : va chercher l'index 0 du tableau maCollec. Dans le tableau que tu récupères, va maintenant chercher l'index 1.

On obtient ainsi cela :

maCollec[0][1] ['0', 'voiture', 'sport', 'rouge'][1] 'voiture'

✎ 08° Sur le même principe que l'exemple précédente, que va répondre l'interpréteur Python à l'instruction suivante ?

>>> maCollec[1][3]

Comment se passer des variables intermédiaires du coup ?

En écrivant plutôt ceci :

1 2 3 4
maCollec = [ # [ début d'un tableau ['0', 'voiture', 'sport', 'rouge'], # virgule comme séparateur ['1', 'helicoptère', 'tourisme', 'marron'], # virgule comme séparateur ['2', 'voiture', 'sport', 'rouge'] ] # ] fin de tableau

On voit bien qu'on ouvre un tableau (crochet rouge) et qu'on y place des tableaux (crochets gris), séparés par des virgules.

Ici, on a ne peut pas créer de tableau par compréhension puisque le contenu n'est pas liée à une expression mathématique. Par contre, on pourrait le créer par extension, en rajoutant au fur et à mesure les nouveaux enregistrements avec la méthode append (to append se traduit par le verbe rajouter).

On sort donc un peu du cadre strict du "tableau informatique de taille fixée" : les vrais tableaux ne disposent pas de cette fonctionnalité.

1 2 3 4
maCollec = [] maCollec.append( ['0', 'voiture', 'sport', 'rouge'] ) maCollec.append( ['1', 'helicoptère', 'tourisme', 'marron'] ) maCollec.append( ['2', 'voiture', 'sport', 'rouge'] )

✎ 09° Utiliser ce programme. Demander dans le Shell le contenu de maCollec Donner l'instruction permettant de rajouter un enregistrement de votre choix. Fournir le code à rajouter dans le programme et le résultat de la variable maCollec après modification.

Dernière question de cette sous-partie : voyons comment visualiser le contenu de notre collection proprement en utilisant les fStrings et leurs capacités à forcer l'affichage sur un nombre précis de caractères (20 ici).

10° Utiliser ce programme qui mémorise une collection et une fonction-procédure visualiser. Taper ensuite visualiser(maCollec) dans le Shell pour voir le contenu de la collection d'enregistrements.

1 2 3 4 5 6 7 8 9
def visualiser(laCollec) : '''Procédure qui affiche proprement le contenu de la collection laCollection''' for enregistrement in laCollec : print(f"{enregistrement[1]:20}{enregistrement[2]:20}{enregistrement[3]:20}") maCollec = [] maCollec.append( ['0', 'voiture', 'sport', 'rouge'] ) maCollec.append( ['1', 'helicoptère', 'tourisme', 'marron'] ) maCollec.append( ['2', 'voiture', 'sport', 'rouge'] )

...CORRECTION...

>>> visualiser(maCollec) voiture sport rouge helicoptère tourisme marron voiture sport rouge

Vous vous doutez bien que nous n'allons pas taper directement le contenu du tableau. Dans la dernière partie, nous verrons comment créer ces tableaux directement à l'aide de fichiers texte au format CSV.

3 - Tableau de tuples

Le problème du tableau de tableaux, c'est que toutes les "cases" doivent contenir le même type d'éléments (que des integers, que des strings ...)

En Python, nous n'utilisons pas réellement des tableaux mais des objets de type list qui permettent d'avoir des types différents dans les cases. Mais, sinon, comment faire ?

Et bien, on pourrait utiliser un tableau de tuples.

Lors de la déclaration, la seule différence vient de la présence de parenthèses.

1 2 3
enr0 = ('0', 'voiture', 'sport', 'rouge') enr1 = ('1', 'hélicoptère', 'tourisme', 'marron') enr2 = ('2', 'voiture', 'sport', 'rouge')

Deux intérêts à cette façon de faire :

  • Si vos tableaux étaient de vrais tableaux, on peut maintenant mettre ce qu'on veut dans les éléments, ils n'ont plus à être de même type.
  • 1 2 3
    enr0 = (0, 'voiture', 'sport', 'rouge') enr1 = (1, 'hélicoptère', 'tourisme', 'marron') enr2 = (2, 'voiture', 'sport', 'rouge')
  • Si vos tableaux étaient des lists-Python, la lecture des tuples est plus rapide que la lecture de lists et les tuples de Python sont non mutables : on est ainsi certain qu'on ne pourra pas modifier involontairement les enregistrements.

4 - Tableau de dictionnaires

Le problème du tableau de tableaux ou du tableau de tuples, c'est qu'il faut connaitre le numéro d'index de l'attribut pour le trouver. C'est un peu pénible.

On peut faire mieux avec les dictionnaires : il suffit de créer un tableau de dictionnaires dont la clé est ... le nom du descripteur (ou attribut) !

1 2 3 4 5
enr1 = {} enr1['id'] = 0 enr1['type'] = 'voiture' enr1['utilisation'] = 'sport' enr1['couleur'] = 'rouge'

Si on place ceci en mémoire, on peut alors lancer ceci dans le Shell par exemple :

>>> enr1['couleur'] 'rouge'

On peut le voir : le problème avec les dictionnaires c'est que c'est long à créer. Nous allons donc automatiser les choses en créant une fonction qui attend un tableau en paramètes et qui renvoie le dictionnaire correspondant.

11° Utiliser ce programme qui utilise la fonction creer pour créer un dictionnaire à partir du tableau de 4 éléments transmis lors de l'appel.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
def creer(entree) : '''Renvoie un dictionnaire ayant les clé id, type, utilisation et couleur :: param entree(list) :: un tableau de 4 éléments correspondant aux clés ci-dessus :: return (dict) :: dictionnaire avec les 4 clés id, type, utilisation et couleur :: exemple :: >>> creer([0, 'voiture', 'sport', 'rouge']) {'id': 0, 'type': 'voiture', 'utilisation': 'sport', 'couleur': 'rouge'} ''' reponse = {} reponse['id'] = entree[0] reponse['type'] = entree[1] reponse['utilisation'] = entree[2] return reponse enr1 = creer([0,'voiture','sport','rouge']) print(enr1)

On obtient le visuel suivant :

{'id': 0, 'type': 'voiture', 'utilisation': 'sport'}

Zut ! Il manque la couleur.

✎ 12° Rajouter la clé couleur dans le code de notre fonction creer. On notera que la couleur est stockée dans l'index 3 du tableau reçu en paramètre.

Maintenant que nous savons créer nos enregistrements, nous n'avons plus qu'à les rajouter par extension dans notre liste-collection. Nous allons donc créer un tableau de dictionnaires.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
def creer(entree) : '''Renvoie un dictionnaire ayant les clé id, type, utilisation et couleur :: param entree(list) :: un tableau de 4 éléments correspondant aux clés ci-dessus :: return (dict) :: dictionnaire avec les 4 clés id, type, utilisation et couleur :: exemple :: >>> creer([0, 'voiture', 'sport', 'rouge']) {'id': 0, 'type': 'voiture', 'utilisation': 'sport', 'couleur': 'rouge'} ''' reponse = {} reponse['id'] = entree[0] reponse['type'] = entree[1] reponse['utilisation'] = entree[2] reponse['couleur'] = entree[3] return reponse # Programme maCollec = [] maCollec.append( creer([0,'voiture','sport','rouge']) ) maCollec.append( creer([1,'hélicoptère','tourisme','marron']) ) maCollec.append( creer([2,'voiture','sport','rouge']) )

13° Utiliser ce programme précédent et afficher ensuite le contenu de la collection maCollection dans le Shell.

Nous obtenons donc un tableau de dictionnaires ayant tous les mêmes clés.

Nous aurions obtenu le même résultat si nous avions tapé ceci à la main :

1 2 3 4
maCollect = [ {'id': 0, 'type': 'voiture', 'utilisation': 'sport', 'couleur': 'rouge'}, {'id': 1, 'type': 'hélicoptère', 'utilisation': 'tourisme', 'couleur': 'marron'}, {'id': 2, 'type': 'voiture', 'utilisation': 'sport', 'couleur': 'rouge'} ]

Les clés sont dans les attributs de notre collection.

Chacun des dictionnaires est l'un des enregistrements.

Comme les dictionnaires ont tous les mêmes clés, on dira que ce sont des p-uplets nommés (4-uplets ici): des séquences de 4 éléments ayant chacun un nom bien particulier.

14° Que va renvoyer le programme si on tape ceci dans le Shell :

>>> maCollec[1]

...CORRECTION...

Il va renvoyer l'index 1 de notre tableau, à savoir un dictionnaire.

{'id': 1, 'type': 'hélicoptère', 'utilisation': 'tourisme', 'couleur': 'marron'}

15° Que va renvoyer le programme si on tape ceci dans le Shell :

>>> maCollec[1]['couleur']

...CORRECTION...

Avec maCollec[1], il va renvoyer l'index 1 de notre tableau, à savoir un dictionnaire.

{'id': 1, 'type': 'hélicoptère', 'utilisation': 'tourisme', 'couleur': 'marron'}

Si on cherche la clé 'couleur', il va donc renvoyer marron. Et voilà.

Il est temps maintenant de voir comment on peut parvenir à récupérer des données libres pour en faire quelque chose.

5 - CSV

Vous avez vu en SNT qu'il existe des formats courants de données. Cela permet de créer des données et de les distribuer dans un format qui sera facilement utilisable par quelqu'un d'autre.

On pourra croire qu'on peut simplement créer des fichiers Python avec des tableaux de tableaux ou des tableaux de dictionnaires, mais comment faire si quelqu'un veut récupérer vos données avec un autre langage que Python ?

L'un des formats les plus répandus est le format CSV.

CSV et TSV

C'est un moyen simple de transmettre des données : on écrit un simple fichier texte.

Il sera compréhensible par n'importe quel langage de programmation et n'importe quel tableur.

CSV veut dire Comma Separated Values : littéralement, des valeurs séparées par des virgules !

La première ligne du fichier texte contient usuellement les intitulés des attributs (les colonnes).

Chaque valeur est bien séparée des autres par une virgule.

Chaque ligne du fichier texte correspond à un enregistrement. Le retour à la ligne (Line Feed) correspond dans le fichier texte à un octet bien particuler, 10, représenté par \n en Python. Tout programme est donc capable de le détecter.

Un exemple :

1 2 3 4
#,Name,Type 1,Type 2,Total,HP,Attack,Defense,Sp. Atk,Sp. Def,Speed,Generation,Legendary 1,Bulbasaur,Grass,Poison,318,45,49,49,65,65,45,1,False 2,Ivysaur,Grass,Poison,405,60,62,63,80,80,60,1,False 3,Venusaur,Grass,Poison,525,80,82,83,100,100,80,1,False

Si on rajoute les éléments importants en rouge (dont le passage à la ligne (invisible à l'affichage)):

1 2 3 4
#,Name,Type 1,Type 2,Total,HP,Attack,Defense,Sp. Atk,Sp. Def,Speed,Generation,Legendary 1,Bulbasaur,Grass,Poison,318,45,49,49,65,65,45,1,False 2,Ivysaur,Grass,Poison,405,60,62,63,80,80,60,1,False 3,Venusaur,Grass,Poison,525,80,82,83,100,100,80,1,False

La première colonne est donc celle de l'attribut #, soit un nombre, un simple identifiant.

La deuxième colonne correspond au nom du pokemon.

Les deux suivantes correspondantes à ces deux types ...

On trouve des variables du CSV.

L'élément séparateur virgule est très courant. L'octet symbolisant une virgule contient 44.

L'élément séparateur peut être parfois le point-virgule (;), un octet à 59.

L'élement séparateur peut être la tabulation, un octet à 9. On parle alors de TSV, Tabulated Separated Values.

Mais ça ne change rien au principe : il faut juste connaître l'élément séparateur utilisé pour parvenir à bien séparer les éléments.

16° Aller à l'adresse Github suivante (ou faire une simple recherche dans un moteur de recherche sur CSV + Pokemon): CSV POKEMON GITHUB.

Vous devriez aboutir sur une page qui vous présente visuellement le fichier sous la forme d'un tableau, comme un tableur.

Une définition : celle d'encodage

Appuyer sur le bouton RAW : vous devriez voir le vrai contenu de ce fichier.

Et voilà, un beau fichier CSV, à savoir un fichier texte qui possède juste un nom qui finit en .csv.

17° Enregistrer le fichier (Enregister sous dans votre navigateur. Ouvrir ce fichier avec votre tableur habituel. Si vous ne parvenez pas à télécharger le fichier, voici un lien avec un copier depuis infoforall : LE FICHIER CSV.

Avec OpenCalc de LibreOffice, on obtient la page d'accueil suivante :

Tableur

Il faut lui dire l'encodage utilisé (à priori UTF-8 si le fichier est récent, c'est le plus commun actuellement) ainsi que le caractère séparateur.

Ensuite, on lance et on obtient ceci :

CSV dans un tableur

Comment parvenir à créer un tableau de dictionnaires avec cela ?

C'est le but de la partie suivante.

6 - Fichier CSV et Python

Sur le principe :

  • On ouvre le fichier en lecture
  • On lit la première ligne qu'on transforme en tableau contenant les noms des attributs
  • On lit chaque ligne suivante en la décomposant en tableau
  • On transforme ce tableau en dictionnaire en utilisant les clés trouvées précédemment.
  • On rajoute notre enregistrement-dictionnaire dans le tableau-collection
  • On ferme le fichier

Il est temps de faire à quoi ressemble ce fichier.

Vous allez simplement le mettre en mémoire : il n'est constitué que de trois fonctions qu'on place en mémoire. Nous allons progressivement apprendre à les manipuler et les comprendre.

✎ 18° Placer le programme ci-dessous en mémoire. Nous allons commencer par tenter de comprendre la fonction decomposer.

Utiliser ensuite les instructions dans les Shell pour comprendre comment la fonction fonctionne.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
def decomposer(chaine, separateur) : '''Fonction qui décompose la chaine et créant un tableau contenant les valeurs :: chaine (str) :: la chaîne de caractères à décomposer :: separateur (str) :: le caractère de séparation :: return (list) :: un tableau contenant les différents éléments :: exemple :: >>> decomposer('1,voiture,sport,rouge', ',') ['1', 'voiture', 'sport', 'rouge'] ''' chaine = chaine.replace('\n', '') # On supprime le passage à la ligne chaine = chaine.replace('\r', '') # On supprime le retour chariot tableau = chaine.split(separateur) # On crée un tableau à partir de la chaine return tableau def creer(entree, attributs) : '''Renvoie un dictionnaire à partir de entree avec les clés fournies dans attributs :: param entree(list) :: un tableau de X éléments :: param attributs(list) :: un tableau de X éléments également :: return (dict) :: le dictionnaire voulu :: exemple :: >>> creer([0, 'voiture', 'sport', 'rouge'], ['id', 'type', 'utilisation', 'couleur']) {'id': 0, 'type': 'voiture', 'utilisation': 'sport', 'couleur': 'rouge'} ''' reponse = {} if len(entree) == len(attributs) : for index in range(len(entree)) : reponse[attributs[index]] = entree[index] return reponse def creer_collection(nom_fichier) : '''Fonction qui renvoie un tableau de dictionnaire à partir d'un fichier CSV :: param nom_fichier(str) :: le nom du fichier CSV correct à traiter :: return (list) :: le tableau de dictionnaires ''' # 1 - On crée une tableau vide laCollec = [] # 2 - On ouvre le fichier en lecture monFichier = open(nom_fichier, 'r', encoding='utf-8') # 3 - On lit la première ligne pour créer le tableau des attributs entete = monFichier.readline() # entete est un simple string qui finit par \n attributs = decomposer(entete, ',') # création d'un tableau contenant les attributs # 4 - On lit la suite du fichier ligne par ligne for ligne in monFichier : valeurs = decomposer(ligne, ',') # tableau contenant les valeurs enregistrement = creer(valeurs, attributs) # dictionnaire clé-valeur laCollec.append(enregistrement) # rajout à la collection # 5 - On ferme le fichier monFichier.close() # On ferme le fichier # 6 - On renvoie la collection return laCollec
>>> attributs = decomposer('#,Name,Type 1,Type 2,Total\n', ',') >>> attributs ['#', 'Name', 'Type 1', 'Type 2', 'Total']

Répondre alors aux question suivantes :

  • A quoi sert la ligne 12 ?
  • Que fait la ligne 14 ?
  • Que renvoie la fonction ? Une liste, une dictionnaire ou un string ?

La fonction creer fonctionne un peu comme celle de la partie précédente : elle crée un dictionnaire à partir d'un tableau. La différence ici est qu'elle attend deux tableaux : le tableau entree contient les valeurs aux index 0, 1, 2 ... et le tableau attributs contient les noms des clés correspondantes aux index 0, 1, 2...

On envoie le tableau d'entrée ['voiture', 'rouge'] et le tableau d'attributs ['type', 'couleur'] et la fonction crée ceci {'type': 'voiture', 'couleur': 'rouge'}.

L'avantage est que notre programme fonctionne sur tous les fichiers CSV. Si on donne les noms des attributs à la main, cela implique de changer de programme dès qu'on change de fichier.

✎ 19° Utiliser le code suivant et expliquer la réponse que vous allez obtenir. Il faudra notamment clairement réaliser l'étape des lignes 30 et 31 sur les 2 premières étapes (index valant 0 et 1).

>>> attributs = decomposer('#,Name,Type 1,Type 2,Total\n', ',') >>> ligne_suivante = decomposer("1,Bob,Feu,Terre,58\n", ',') >>> enregistrement = creer(ligne_suivante, attributs) >>> enregistrement

Il nous reste à voir la fin : la lecture du fichier ligne par ligne. Rien de compliqué.

On commence par déclarer la fonction, créer un tableau vide qui contiendra notre collection d'enregistrements.

On ouvre le fichier et on ne lit que la première ligne à l'aide de la méthode readline. Le pointeur de lecture se postionne donc après cette première ligne ensuite.

34 35 36 37 38 39 40 41 42 43 44 45 46 47
def creer_collection(nom_fichier) : '''Fonction qui renvoie un tableau de dictionnaire à partir d'un fichier CSV :: param nom_fichier(str) :: le nom du fichier CSV correct à traiter :: return (list) :: le tableau de dictionnaires ''' # 1 - On crée une tableau vide laCollec = [] # 2 - On ouvre le fichier en lecture monFichier = open(nom_fichier, 'r', encoding='utf-8') # 3 - On lit la première ligne pour créer le tableau des attributs entete = monFichier.readline() # entete est un simple string qui finit par \n

Le début du fichier CSV est :

1 2 3 4
#,Name,Type 1,Type 2,Total,HP,Attack,Defense,Sp. Atk,Sp. Def,Speed,Generation,Legendary 1,Bulbasaur,Grass,Poison,318,45,49,49,65,65,45,1,False 2,Ivysaur,Grass,Poison,405,60,62,63,80,80,60,1,False 3,Venusaur,Grass,Poison,525,80,82,83,100,100,80,1,False

La variable entete va donc contenir le STRING siuvant :

entete = "#,Name,Type 1,Type 2,Total,HP,Attack,Defense,Sp. Atk,Sp. Def,Speed,Generation,Legendary\n"

Lorsqu'on appliquera la ligne 48 qui décompose entete, on va donc obtenir le tableau attributs suivant :

attributs = ['#', 'Name', 'Type 1', 'Type 2', 'Total', 'HP', 'Attack', 'Defense', 'Sp. Atk', 'Sp. Def', 'Speed', 'Generation', 'Legendary']

Ensuite, on lit la totalité du fichier CSV, une ligne à la fois :

  • On transforme la ligne*-string en tableau avec la fonction decomposer
  • On utilise le tableau de valeurs et le tableau d'attributs pour créer un dictionnaire-enregistrement avec creer
  • On rajoute l'enregistrement dans le tableau de la collection avec la méthode append.
50 51 52 53 54
# 4 - On lit la suite du fichier ligne par ligne for ligne in monFichier : valeurs = decomposer(ligne, ',') # tableau contenant les valeurs enregistrement = creer(valeurs, attributs) # dictionnaire clé-valeur laCollec.append(enregistrement) # rajout à la collection

C'est fini. On a lu toutes les lignes. On ferme le fichier et on renvoie le tableau qui contient l'ensemble des enregistrements-dictionnaires.

56 57 58 59 60
# 5 - On ferme le fichier monFichier.close() # On ferme le fichier # 6 - On renvoie la collection return laCollec

✎ 20° Utiliser le programme pour trouver approximativement les 4 premiers enregistrements (à la main, nous verrons dans la prochaine activité comme le faire par programmation).

>>> a = creer_collection('pokemon.csv') >>> a

Si on cherche à le présenter de façon plus correct, ça donne ceci :

[ {'#': '1', 'Name': 'Bulbasaur', 'Type 1': 'Grass', 'Type 2': 'Poison', 'Total': '318', 'HP': '45', 'Attack': '49', 'Defense': '49', 'Sp. Atk': '65', 'Sp. Def': '65', 'Speed': '45', 'Generation': '1', 'Legendary': 'False'}, {'#': '2', 'Name': 'Ivysaur', 'Type 1': 'Grass', 'Type 2': 'Poison', 'Total': '405', 'HP': '60', 'Attack': '62', 'Defense': '63', 'Sp. Atk': '80', 'Sp. Def': '80', 'Speed': '60', 'Generation': '1', 'Legendary': 'False'}, {'#': '3', 'Name': 'Venusaur', 'Type 1': 'Grass', 'Type 2': 'Poison', 'Total': '525', 'HP': '80', 'Attack': '82', 'Defense': '83', 'Sp. Atk': '100', 'Sp. Def': '100', 'Speed': '80', 'Generation': '1', 'Legendary': 'False'}, {'#': '3', 'Name': 'VenusaurMega Venusaur', 'Type 1': 'Grass', 'Type 2': 'Poison', 'Total': '625', 'HP': '80', 'Attack': '100', 'Defense': '123', 'Sp. Atk': '122', 'Sp. Def': '120', 'Speed': '80', 'Generation': '1', 'Legendary': 'False'},

La question notée : chercher sur le Web un autre fichier de votre choix en tapant une recherche du type "CSV opendate un truc".

Télécharger le fichier sur votre ordinateur. Me fournir l'URL du fichier CSV et les 6 premiers enregistrements.

Quelques exemples possibles :

  • Les naufragés du Titanic : TITANIC (attention, c'est un fichier TSV : c'est la tabulation \t qui sépare les élements ; pensez à modifier la virgule en \t lors des appels à décomposer aux lignes 54 et 58)
  • La liste des cas de COVID-19 dans le monde : COVID
  • Les villes françaises : base-donnees-villes-francaises

7 - FAQ

Pour l'instant on doit créer le fichier CSV à la main. On ne peut pas les récupérer automatiquement ?

Oui, sans problème. Je vous montre ici deux façons de réaliser cela.

La façon la plus basique et la plus facile, utilisant l'un des modules de base présent dans la distribution Python. Et une façon plus complexe, basée sur un module extérieur utilisant le module précédent.

Module urllib

Ce module est présent dans votre distribution Python normalement.

Voici comment parvenir à télécharger un fichier et à l'enregistrer dans le même dossier que celui où est stocké le fichier Python.

1 2
import urllib.request urllib.request.urlretrieve('https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv', 'leFichier.csv')

On doit donc fournir à la fonction urlretrieve deux arguments : le premier est un string contenu l'URL de la ressource et le deuxième est un string contenant le nom d'enregistrement sur votre disque dur.

Facile, rapide et efficace.

Le tout est de trouver une URL valide.

Module requests

Deuxième façon de faire avec un module Python plus complet et basé sur celui que nous venons de voir : requests.

Dans Thonny, aller dans le menu TOOLS - MANAGE PACKAGES. Lancer une recherche sur et installer le module requests.

1 2 3 4
import requests reponse = requests.request(url='https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv', method='GET') chaine_reponse = reponse.text print(text)

Il nous reste donc simplement à enregister cela dans un fichier csv, avec l'option w pour indiquer qu'on veut l'écrire donc.

1 2 3 4 5
import requests reponse = requests.request(url='https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_19-covid-Confirmed.csv', method='GET') fichier = open('mesdonnees.csv', 'w', encoding='utf-8') fichier.write(reponse.text) fichier.close()

Et voilà. Vous pouvez aller voir, vous venez de récupérer le fichier sur votre ordinateur.

Il suffit de rajouter ceci au début du programme général et ça marche maintenant sans avoir besoin de faire des copier-coller et autres choses automatisables.

Et ça fonctionne avec toutes pages accessibles. Le module permet même de s'identifier pourvu que vous connaissiez l'identifiant et le mot de passe. Vous commencez à vous rendre compte qu'on peut récupérer TOUT ce que vous postez sur le Web ? Ca fait peur, non ?

Maintenant vous savez chercher des fichiers CSV, les charger en mémoire et les transformer en collection.

Votre collection peut être :

  • un tableau de tableaux (si tous les éléments des enregistrements sont de même type)
  • un tableau de tuples (si les éléments ne sont pas de même type)
  • un tableau de dictionnaires (si vous voulez accéder aux descripteurs par leurs noms et pas avec un numéro d'index)

Dans la partie Données, nous allons voir les algorithmes nous permettant de les parcourir, et d'y réaliser du traitement d'informations.

C'est bien beau d'avoir des informations en mémoire. Le problème c'est de les exploiter.

Activité publiée le 08 03 2020
Dernière modification : 15 04 2020
Auteur : ows. h.