Après avoir découvert le format CSV, nous allons maintenant, à l'aide de Python, apprendre à effectuer, dans un notebook, des traitements sur ces données.
Pour traiter des données, nous allons utiliser la bibliothèque Python csv
.
Pour nos premiers pas avec csv, nous allons utiliser des données très simples au format CSV : ces données sont contenues dans le fichier : personnes.csv
I. Lecture d'un fichier csv
1. Méthode avec csv.reader
a) Lire et comprendre le fichier csv comme une liste de listes
⏬ Exécutez le code ci-dessous
import csv
with open('personnes.csv', mode = "r" , encoding='utf-8' , newline = '') as csvFile :
reader = csv.reader(csvFile)
lu = [ligne for ligne in reader]
# voyons le résutat :
print(lu)
for ligne in lu :
print(ligne)
Le code ci-dessus est très simple :
csv
.La première liste correspond au nom des entêtes des colonnes de la table (les descripteurs) ;
Les listes suivantes contiennent respectivement les données enregistrées dans chaque ligne de la table (les enregistrements).
➽ Ecrire une fonction qui lit un fichier et renvoie la liste de listes
def readCSV1(filename: str ) -> list :
'''
Entrée : nom d'un fichier CSV
Sortie : la fonction renvoie les données lues dans une liste de listes
'''
pass
✅ vérification
personnes = readCSV1('personnes.csv')
assert personnes == [['nom', 'prenom', 'age'], ['Durand', 'Jean-Pierre', '32'], ['Dupont', 'Christophe', '51'], ['Terta', 'Henry', '37'], ['Kapri', 'Leon', '45'], ['Lenard', 'Michel', '17'], ['Lenard', 'Georges', '15'], ['Herpan', 'stephan', '22'], ['Mastic', 'Brice', '61'], ['Pouyeau', 'Maxime', '27'], ['Arox', 'Gilles', '51'], ['Follin', 'Paul', '32']]
2. Méthode avec csv.DictReader
a) Lire et comprendre le fichier csv en utilisant une liste de dictionnaires
import csv
with open('personnes.csv', mode = "r", encoding='utf-8', newline = '') as csvFile :
reader = csv.DictReader(csvFile)
lu = [dict(ligne) for ligne in reader]
# voyons le résutat :
print(lu)
Plutôt qu’une liste de listes, une instruction permet d’obtenir chaque enregistrement au format dictionnaire : dict.
On obtient ainsi une liste de dictionnaires, à savoir :
listeDico = [ {clé1:enr1_val1, clé2:enr1_val2, …},
{clé1:enr2_val1, clé2:enr2_val2, …},
{clé1:enr3_val1, clé2:enr3_val2, …} ]
Une telle structure est mieux adaptée. D'une part, les en-têtes (descripteurs) ne sont plus lus comme une ligne banale mais sont utilisées comme clefs dans les dictionnaires. D'autre part, chaque élément listeDico[i] est un dictionnaire et il sera plus facile de manipuler :
listeDico[i] = {'classe':'TG1' , 'nb_elev':'34', 'nb_garçons':'16' , 'nb_filles':'18' , 'nb_admis':'33', …}
plutôt que : listeDico[i] = ['TG1','34', 16 , 18 , '33', …]
Dans un fichier avec beaucoup de colonnes, il est assez fastidieux de se souvenir a quoi correspond l'indice d'une colonne. dans l'exemple, listeDico[i][3] est le nombre de filles, tandis que avec le dictionnaire on écrira listeDico[i]['nb_filles']. Et imaginez quand il y a beaucoup de colonnes, comme il est difficile de retrouver quel indice de colonne correspond à quoi...
➽ Ecrire une fonction qui lit un fichier et renvoie la liste de dictionnaires
def readCSV( filename:str ) -> list :
'''
Entrée : nom d'un fichier CSV
Sortie : la fonction renvoie les données lues dans une liste de dictionnaires
'''
pass
✅ vérification
personnes = readCSV('personnes.csv')
for elem in personnes :
print(elem)
assert personnes == [{'nom': 'Durand', 'prenom': 'Jean-Pierre', 'age': '32'}, {'nom': 'Dupont', 'prenom': 'Christophe', 'age': '51'}, {'nom': 'Terta', 'prenom': 'Henry', 'age': '37'}, {'nom': 'Kapri', 'prenom': 'Leon', 'age': '45'}, {'nom': 'Lenard', 'prenom': 'Michel', 'age': '17'}, {'nom': 'Lenard', 'prenom': 'Georges', 'age': '15'}, {'nom': 'Herpan', 'prenom': 'stephan', 'age': '22'}, {'nom': 'Mastic', 'prenom': 'Brice', 'age': '61'}, {'nom': 'Pouyeau', 'prenom': 'Maxime', 'age': '27'}, {'nom': 'Arox', 'prenom': 'Gilles', 'age': '51'}, {'nom': 'Follin', 'prenom': 'Paul', 'age': '32'}]
Quelle est la différence entre csv.reader(mon_fichier)
et csv.DictReader(mon_fichier)
?
Réponse : ...
II. Extraire des données suivant certains critères
Nous désirons sélectionner des données suivant un certain critère, par exemple trouver tous les renseignements de M. Herpan, ou trouver toutes les personnes âgées de moins de 30 ans... Quelle syntaxe allons-nous choisir?
1. Trouver tous les renseignements des personnes portant le nom "Lenard"
infos = [p for p in personnes if p['nom'] == 'Lenard']
for elem in infos :
print(elem)
[p for p in personnes if p['nom'] == 'Lenard']
Dans ce premier exemple on a sélectionné tous les informations, donc on prend, pour chaque dictionnaire p de la liste, tout le dictionnaire.
En revanche on a mis un critère de sélection (un filtre) sur le nom.
Si on voulait extraire par exemple seulemement la colonne nom on prendrait p['nom'] qui est la valeur de la clé nom de chaque dictionnaire p de la table :
Ici le résultat est une liste de noms, et pas une liste de dictionnaire. On pourrait souhaiter (et ce sera souvent utile) conserver la structure en liste de dictionnaire, de la façon suivante :
On pourrait aussi extraite une seule colonne, sans critère de sélection (filtre) des enregistrements :
Ou bien pour sélectionner plusieurs colonnes :
Rappel sur les contructions de listes, avec append ou en compréhension :
l = []
for i in [3,4,7] :
l.append(i)
l
v = [i for i in range(10) if i%3 == 0]
v
2. Trouver tous les renseignements des personnes âgées de plus de 30 ans
plus30 = [ ... A VOUS ...]
for pers in plus30 :
print(pers)
➽ afficher les noms et prénoms des personnes de plus de 30 ans
# votre code
➽ afficher les noms et prénoms des personnes dont le nom commence par M
# votre code
➽ afficher l'age moyen des personnes dans le fichier
# il faut extraire une liste des ages, puis calculer la moyenne avec sum() et len()
➽ afficher tous les noms en ordre alphabétique
# il faut extraire une liste de noms puis trier avec .sort()
➽ afficher toutes les informations en triant les noms en ordre alphabétique
# si on essaye de trier avec sort() comme ci-dessus :
infos = [ p for p in personnes ]
infos.sort()
print( noms )
# essayez...
# une première solution : extraire les noms, trier la liste, puis
# parcourir la liste pour récuppérer et afficher les infos...
# mais....
noms = [p['nom'] for p in personnes]
noms.sort()
infos = []
for nom in noms :
for p in personnes :
if p['nom'] == nom :
infos.append(p)
for elem in infos :
print( elem )
# essayez...
Vous remarquez qu'on a doublonné Lenard Michel et Georges... pouvez expliquer pourquoi ?
Dans le corrigé vous verrez qu'on pourrait quand même s'en sortir avec cette approche. Mais c'est très inélégant, et très peu efficace...
Tout ceci est un peu fastidieux et ce n'est pas la bonne méthode pour trier nos données, mais pour vous en convaincre il fallait commencer ainsi...
Nous allons voir dans la deuxième partie la bonne façon d'opérer des tris.
III. Trier les données suivant certaines colonnes
Tri sur un unique critère
Reprenons notre tableau initial, nommé personnes :
personnes = readCSV('personnes.csv')
Trier ce tableau avec personnes.sort() n'aurait aucun sens et provoque une erreur :
personnes.sort()
Comprenons bien ceci : TypeError: '<' not supported between instances of 'dict' and 'dict'
❓ Que nous dit l'interpréteur ?
Pour trier, il faut faire des comparaisons entre les éléments. Or ici, nos éléments sont des dictionnaires. '<' n'est pas possible entre dict et dict : on ne peut comparer deux dictionnaires.
Et c'est assez logique, comment comparer Durand Jean-Pierre 32 ans et Tetra Henry 37 ans ? sur l'age ? le nom ? Nous n'avons pas précisé !
C'est ce que nous allons faire en définissant une 🔑 clé de tri
# Une clé est une fonction qui prend en argument un dictionnaire et renvoie la valeur associée à une clé du dictionnaire.
def ma_fonction ( dictionnaire ) :
return dictionnaire['en_tete_colonne']
# Cette fonction sera associée à l’argument key de la méthode sort() :
personnes.sort ( key = ma_fonction ) # Notez que key prend pour valeur le nom de la fonction sans les parenthèses.
# Créez 2 clés avec notre dictionnaire
def cle_age(dico) :
return int(dico['age'])
def cle_nom(dico) :
return dico['nom']
# Faire un tri par age :
personnes.sort( key = cle_age )
# affichage du résultat :
for p in personnes :
print(p)
# ou par age décroissant :
personnes.sort( key = cle_age , reverse=True)
# affichage du résultat :
for p in personnes :
print(p)
# ou par noms :
personnes.sort( key = cle_nom )
# affichage du résultat :
for p in personnes :
print(p)
Auteurs : Jean-Louis Thirot - Mireille Coilhac
Publié sous licence CC BY-NC-SA
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.