14 - Traitement de données en tables
Cours associé : 14 - CSV .
QCM – vérification des prérequis
Pour chaque question, une seule réponse est correcte.
1. Qu’est-ce qu’un fichier CSV ?
- A. Un fichier image compressé
- B. Un fichier texte dont les données sont séparées par un caractère délimiteur (virgule, point-virgule…)
- C. Un fichier binaire utilisé par les bases de données
- D. Un fichier exécutable Python
Correction publiée après la séance.
2. En Python, quel module permet de lire un fichier CSV avec des dictionnaires ?
- A.
json - B.
csv - C.
os - D.
math
Correction publiée après la séance.
3. Que renvoie csv.DictReader lorsqu’on itère dessus ?
- A. Une liste de listes
- B. Un dictionnaire unique contenant toutes les données
- C. Un itérateur de dictionnaires, un par ligne
- D. Une chaîne de caractères
Correction publiée après la séance.
4. On a défini la fonction note(d), qui renvoie d["note"]. Comment trier une liste de dictionnaires suivant la clé "note" ?
- A.
liste.sort() - B.
sorted(liste, key=note) - C.
liste.filter("note") - D.
sorted(liste)
Correction publiée après la séance.
Le TP porte sur un jeu de données ouvertes concernant les prénoms donnés en France de 1900 à 2024 : le fichier à utiliser, prenoms.csv, se télécharge dans la partie « Présentation des données » ci-dessous.
TP : exploration du fichier des prénoms
Dans ce TP, vous allez explorer un jeu de données réel issu de l’INSEE : le fichier des prénoms attribués aux enfants nés en France depuis 1900. Vous apprendrez à importer, rechercher, trier et fusionner des données organisées en tables. Durée : 5 à 6 heures.
Compétences à acquérir : importer une table depuis un fichier CSV ; rechercher les lignes d’une table vérifiant des critères exprimés en logique propositionnelle ; recherche de doublons, tests de cohérence ; trier une table suivant une colonne ; construire une nouvelle table en combinant les données de deux tables ; notion de domaine de valeurs.
Les données utilisées proviennent de l’INSEE et sont placées sous licence ouverte.
Présentation des données
Télécharger l’archive prenoms.zip
et la décompresser dans votre répertoire de travail : elle contient le fichier prenoms.csv (13 Mo, plus de 700 000 lignes) des prénoms attribués aux enfants nés en France entre 1900 et 2024. Il est composé de quatre colonnes (descripteurs) :
sexe:1pour masculin,2pour féminin ;prenom: le prénom, en majuscules et avec ses accents (par exempleSTÉPHANIEouLÉA) ;periode: l’année de naissance ;valeur: le nombre de naissances (arrondi au multiple de 5).
Extrait du fichier :
sexe;prenom;periode;valeur
1;AARON;1980;5
1;AARON;1990;25
1;AARON;2000;120
1;AARON;2010;1605
2;EMMA;2000;6845
2;EMMA;2010;6400
Import des données
Exercice 1 : chargement du fichier CSV.
Compléter la fonction
charger_csvci-dessous. Cette fonction prend en paramètre le nom d’un fichier CSV et renvoie une liste de dictionnaires.Remarque. La fonction
csv.DictReaderlit toutes les valeurs comme des chaînes de caractères. Par exemple,ligne['valeur']vaut'295'(une chaîne) et non295(un entier). Il faut donc convertir les valeurs numériques en entiers pour pouvoir faire des calculs.import csv def charger_csv(nom_fichier): """ Charge un fichier CSV et renvoie une liste de dictionnaires. Chaque dictionnaire représente une ligne du fichier. """ table = [] with open(nom_fichier, 'r', encoding='utf-8') as fichier: lecteur = csv.DictReader(fichier, delimiter=';') for ligne in lecteur: # À COMPLÉTER : convertir les chaînes en entiers ligne['valeur'] = ... ligne['periode'] = ... table.append(ligne) return table # Chargement des données prenoms = charger_csv('prenoms.csv')Indice
int(...)convertit une chaîne en entier : appliquer cette conversion àligne['valeur']et àligne['periode'].Écrire l’instruction qui affiche le nombre total de lignes dans la table.
Indice
La table est une liste : son nombre de lignes est sa longueur.
Écrire une boucle qui affiche les 5 premières lignes de la table. Que représente chaque ligne ?
Indice
prenoms[i]est la ligne d’indicei, et une bouclefor i in range(5):suffit. Lire les clés et les valeurs d’une ligne pour dire ce qu’elle décrit.Écrire l’instruction qui affiche les descripteurs (les clés) de la première ligne.
Indice
La première ligne,
prenoms[0], est un dictionnaire : la méthodekeys()donne ses clés.
Correction publiée après la séance.
Exercice 2 : tests de cohérence.
Avant d’exploiter des données, il est important de vérifier leur cohérence.
Écrire une fonction
verifier_sexe(table)qui prend en paramètre une table et renvoieTruesi toutes les valeurs du descripteursexesont'1'ou'2', etFalsesinon.Indice
Parcourir les lignes et renvoyer
Falsedès qu’une valeur deligne['sexe']n’est ni'1'ni'2'; après la boucle, toutes les lignes sont correctes : renvoyerTrue.Code à copier puis compléter
def verifier_sexe(table): for ligne in table: if ligne['sexe'] != '1' and ...: return ... return TrueÉcrire une fonction
annees_presentes(table)qui prend en paramètre une table et renvoie la liste des années présentes (sans doublons).Indice
Partir d’une liste vide et n’y ajouter l’année d’une ligne que si elle n’y figure pas déjà (
not in).Code à copier puis compléter
def annees_presentes(table): annees = [] for ligne in table: if ... not in annees: annees.append(...) return anneesEn utilisant cette fonction, vérifier s’il y a des années manquantes entre 1900 et 2024.
Indice
Parcourir les années de 1900 à 2024 avec
range(1900, 2025)et garder celles qui ne sont pas dans la liste renvoyée parannees_presentes.
Correction publiée après la séance.
Recherche dans une table
Exercice 3 : recherche simple.
Écrire une fonction
rechercher_prenom(table, prenom)qui prend en paramètres une table et un prénom (chaîne de caractères), et renvoie la liste de toutes les lignes dont le descripteurprenomest égal au prénom cherché.Indice
Parcourir la table et ajouter à une liste résultat chaque ligne dont
ligne['prenom']est égal au prénom cherché.Code à copier puis compléter
def rechercher_prenom(table, prenom): resultats = [] for ligne in table: if ...: resultats.append(...) return resultatsUtiliser cette fonction pour récupérer toutes les lignes correspondant au prénom
'CLAUDE'. Afficher, pour chaque ligne, l’année, le nombre de naissances et le sexe.Indice
Appeler
rechercher_prenom(prenoms, 'CLAUDE'), puis parcourir la liste obtenue et afficherligne['periode'],ligne['valeur']etligne['sexe']avec une f-string.Écrire une fonction
total_naissances(table, prenom)qui prend en paramètres une table et un prénom, et renvoie le nombre total de naissances pour ce prénom (somme des valeurs du descripteurvaleur).Indice
Un accumulateur part de 0 ; pour chaque ligne du prénom cherché, on lui ajoute
ligne['valeur'].Calculer le total des naissances pour le prénom
'MARIE'puis pour le prénom'JEAN'.Question personnelle : rechercher votre propre prénom (en majuscules) et calculer le nombre total de naissances. Que pouvez-vous dire sur la popularité de votre prénom ?
Correction publiée après la séance.
Exercice 4 : recherche avec plusieurs critères.
On souhaite rechercher des lignes vérifiant plusieurs critères à la fois.
Écrire une fonction
rechercher(table, sexe, annee)qui prend en paramètres une table, un sexe ('1'ou'2') et une année (entier), et renvoie la liste des lignes vérifiant ces deux critères simultanément.Indice
Même parcours que
rechercher_prenom, avec une condition qui réunit les deux critères parand:ligne['sexe'] == sexeetligne['periode'] == annee.Utiliser cette fonction pour trouver tous les prénoms féminins attribués en 2020. Combien y en a-t-il ?
Indice
Le sexe féminin est codé
'2', une chaîne, et l’année 2020 est un entier. Le nombre de prénoms est la longueur de la liste obtenue.Combien de prénoms masculins différents ont été attribués en 1950 ? Indication : construire d’abord la liste des lignes correspondantes, puis extraire les prénoms sans doublons.
Indice
Même méthode que
annees_presentesà l’exercice 2 : ajouterligne['prenom']à une liste seulement s’il n’y figure pas encore, puis compter.
Correction publiée après la séance.
Exercice 5 : recherche de doublons.
Certains prénoms sont attribués à la fois à des garçons et à des filles. On appelle ces prénoms des « prénoms mixtes ».
Écrire une fonction
liste_prenoms_par_sexe(table, sexe)qui prend en paramètres une table et un sexe, et renvoie la liste des prénoms (sans doublons) correspondant à ce sexe.Indice
Combiner deux méthodes déjà vues : ne garder que les lignes du sexe demandé, et n’ajouter un prénom à la liste que s’il n’y figure pas encore.
En utilisant cette fonction, construire la liste
masculinsdes prénoms masculins et la listefemininsdes prénoms féminins.Écrire une fonction
prenoms_mixtes(masculins, feminins)qui prend en paramètres ces deux listes et renvoie la liste des prénoms présents dans les deux listes.Indice
Parcourir
masculinset garder chaque prénom qui figure aussi dansfeminins(in).Combien y a-t-il de prénoms mixtes ? Donner quelques exemples.
Indice
La longueur de la liste renvoyée par
prenoms_mixtesdonne le nombre, etmixtes[:10]ses dix premiers éléments.
Correction publiée après la séance.
Tri d’une table
Rappel : trier suivant une colonne. La fonction sorted(table, key=fonction) trie une table : le paramètre key reçoit une fonction qui, appliquée à une ligne, renvoie la valeur à comparer (cours CSV, section « Trier une table suivant une colonne »). Pour ce TP, on utilise les deux fonctions suivantes :
def periode(ligne):
return ligne['periode']
def valeur(ligne):
return ligne['valeur']
Exercice 6 : tri suivant une colonne.
En utilisant
rechercher_prenom, récupérer toutes les lignes correspondant au prénom'EMMA'.Trier cette liste par année croissante en utilisant
emma_trie = sorted(emma, key=periode).Afficher l’évolution du prénom EMMA entre 2000 et 2024 (année et nombre de naissances).
Indice
Parcourir
emma_trieet n’afficher que les lignes dont l’année vérifie2000 <= ligne['periode'] <= 2024.Écrire une fonction
top_prenoms(table, annee, sexe, n)qui prend en paramètres une table, une année, un sexe et un entiern, et renvoie lesnprénoms les plus attribués cette année-là pour ce sexe, triés par nombre de naissances décroissant. Indication : utilisersorted(..., key=valeur, reverse=True).Indice
Trois étapes :
rechercher(table, sexe, annee)donne les lignes de cette année et de ce sexe ;sorted(..., key=valeur, reverse=True)les range de la plus attribuée à la moins attribuée ; la tranche[:n]garde lesnpremières.Code à copier puis compléter
def top_prenoms(table, annee, sexe, n): selection = rechercher(table, ..., ...) selection_triee = sorted(selection, key=valeur, reverse=True) return selection_triee[...]Afficher le top 10 des prénoms féminins en 2024.
Indice
Parcourir le résultat de
top_prenoms(prenoms, 2024, '2', 10)avec les indices, pour afficher le rangi + 1devant chaque prénom.
Correction publiée après la séance.
Exercice 7 : analyse de tendances.
Écrire une fonction
annee_pic(table, prenom)qui prend en paramètres une table et un prénom, et renvoie l’année où ce prénom a été le plus attribué (c’est-à-dire l’année avec le plus grand nombre de naissances). Indication :max(donnees, key=valeur)renvoie la ligne dont la colonne'valeur'est la plus grande.Indice
Récupérer d’abord les lignes du prénom avec
rechercher_prenom, puis la ligne du maximum avecmax(donnees, key=valeur): l’année cherchée est sa valeur'periode'.Code à copier puis compléter
def annee_pic(table, prenom): donnees = rechercher_prenom(table, prenom) ligne_max = max(donnees, key=...) return ligne_max[...]Calculer l’année du pic pour les prénoms suivants :
'BRIGITTE','SYLVIE','NATHALIE','STÉPHANIE','LÉA'. Que remarque-t-on sur la succession de ces prénoms dans le temps ?Indice
Une boucle sur la liste des cinq prénoms appelle
annee_picpour chacun. Ranger ensuite les années obtenues dans l’ordre.Question de réflexion : à votre avis, quels facteurs peuvent influencer les cycles de popularité des prénoms ? Pensez aux médias, aux personnalités célèbres, aux événements historiques…
Correction publiée après la séance.
Fusion de tables
On dispose d’un second fichier origines.csv (à déposer dans votre répertoire de travail) contenant l’origine étymologique de certains prénoms :
prenom;origine;signification
EMMA;germanique;universel ou puissant
GABRIEL;hebreu;force de Dieu
LÉA;hebreu;fatiguee ou lionne
LUCAS;grec;lumiere
JADE;espagnol;pierre verte
LOUIS;germanique;illustre au combat
Exercice 8 : chargement et fusion de deux tables.
Charger le fichier
origines.csvdans une tableorigines(sans conversion de types, car toutes les valeurs sont des chaînes) :def charger_csv_simple(nom_fichier): table = [] with open(nom_fichier, 'r', encoding='utf-8') as fichier: lecteur = csv.DictReader(fichier, delimiter=';') for ligne in lecteur: table.append(ligne) return table origines = charger_csv_simple('origines.csv')Écrire une fonction
fusionner(table1, table2, cle)qui prend en paramètres deux tables et le nom d’un descripteur commun (la clé), et renvoie une nouvelle table contenant les lignes detable1enrichies des informations detable2lorsque les valeurs de la clé correspondent.Principe : pour chaque ligne de
table1, on cherche danstable2une ligne ayant la même valeur pour le descripteurcle. Si on en trouve une, on crée une nouvelle ligne combinant les informations des deux.def fusionner(table1, table2, cle): resultat = [] for ligne1 in table1: # À compléter : parcourir table2 # À compléter : vérifier si la clé correspond # À compléter : créer la nouvelle ligne enrichie return resultatIndice
Deux boucles imbriquées : pour chaque
ligne1, parcourir toutes les lignesligne2detable2. Quandligne1[cle] == ligne2[cle], créer un dictionnaire vide, y recopier toutes les paires deligne1puis celles deligne2, et l’ajouter au résultat.Code à copier puis compléter
def fusionner(table1, table2, cle): resultat = [] for ligne1 in table1: for ligne2 in table2: if ...: nouvelle_ligne = {} for k in ligne1: nouvelle_ligne[k] = ... for k in ligne2: nouvelle_ligne[k] = ... resultat.append(nouvelle_ligne) return resultatFusionner les tables
prenomsetoriginessur la clé'prenom'.Pour chaque prénom présent dans
origines, afficher son origine, sa signification et le nombre de naissances en 2024.Indice
Parcourir la table fusionnée et n’afficher que les lignes de l’année 2024 : chacune contient à la fois
'origine','signification'et'valeur'.
Correction publiée après la séance.
Exercice 9 : notion de domaine de valeurs.
Écrire une fonction
valeurs_distinctes(table, descripteur)qui prend en paramètres une table et le nom d’un descripteur, et renvoie la liste des valeurs distinctes (sans doublons) de ce descripteur dans la table.Indice
Même méthode que
annees_presentes, avecligne[descripteur]à la place deligne['periode'].Appliquer cette fonction au descripteur
'origine'de la tableorigines. La liste obtenue s’appelle le domaine de valeurs du descripteur.Quel est le domaine de valeurs du descripteur
'sexe'dans la tableprenoms?Indice
Appeler
valeurs_distinctessur la tableprenomsavec le descripteur'sexe', ou se souvenir du test de cohérence de l’exercice 2.
Correction publiée après la séance.
Pour aller plus loin
Exercice 10 : synthèse, portrait d’un prénom.
Écrire une fonction portrait_prenom(table, prenom) qui prend en paramètres une table et un prénom, et affiche un résumé complet de ce prénom :
- le nombre total de naissances ;
- l’année du pic de popularité et le nombre de naissances cette année-là ;
- la répartition entre masculin et féminin (en pourcentage) ;
- la première et la dernière année d’apparition dans les données.
Tester la fonction avec les prénoms 'CAMILLE', 'DOMINIQUE' et 'CLAUDE'.
Indice
Réutiliser ce qui a déjà été écrit : rechercher_prenom pour les lignes du prénom, un accumulateur pour le total, max(..., key=valeur) pour le pic, deux accumulateurs (un par sexe) pour la répartition, et min et max sur la liste des années.
Correction publiée après la séance.
Autres jeux de données
Exercice 11 : requêtes sur les villes de France.
Le fichier villes.csv décrit les communes françaises (nom, département, population en 2012, densité, altitude minimale, etc.). Écrire les programmes Python qui répondent aux questions suivantes.
Indice
Ce fichier utilise la virgule comme séparateur : csv.DictReader(fichier, delimiter=','). Ses descripteurs sont dep, nom, nb_hab_2012, dens, alt_min, etc., et toutes les valeurs sont lues comme des chaînes : convertir avec int() avant de comparer des nombres. Le Rhône est le département '69'.
Donner la liste des villes du Rhône qui ont une altitude minimale supérieure à 500 m.
Indice
Même parcours que
rechercherà l’exercice 4, avec la conditionligne['dep'] == '69' and int(ligne['alt_min']) > 500.Donner la liste des villes du Rhône qui ont une densité d’habitants inférieure à 200 hab/km² (la table contiendra trois colonnes : le nom de la ville, la densité de la population et l’altitude minimale).
Indice
Pour chaque ville retenue, ajouter au résultat un nouveau dictionnaire qui ne garde que trois clés :
{'nom': ..., 'dens': ..., 'alt_min': ...}.Donner la liste de toutes les villes françaises ayant une densité de population supérieure à 50 hab/km² et une altitude minimale supérieure à 1500 m.
Indice
Une seule condition réunit les deux critères avec
and, sans critère de département.Donner le nombre d’habitants du Rhône en 2012.
Indice
Additionner
int(ligne['nb_hab_2012'])pour toutes les villes du département'69'.Trier les données de façon à obtenir la ville française ayant l’altitude minimale la plus élevée.
Indice
Écrire une fonction
alt_min(ligne)qui renvoieint(ligne['alt_min']), puis trier avecsorted(villes, key=alt_min, reverse=True): la ville cherchée est la première.Quelle est la ville française ayant la densité de population la plus forte ?
Indice
Même méthode avec la densité, ou directement
max(villes, key=...)avec une fonction qui renvoieint(ligne['dens']).
Exercice 12 : concaténation et jointure.
Les communes du département des Alpes-Maritimes ont été oubliées dans le fichier
villes.csvet se trouvent dans le fichier villes-06.csv . Les descripteurs étant les mêmes dans les deux fichiers, écrire un programme Python permettant de fusionner les deux tables.Indice
Les deux tables ont les mêmes descripteurs : il suffit de mettre les lignes de la seconde à la suite de celles de la première, avec
+ou avec une boucle etappend.On dispose de deux fichiers clients.csv et commandes.csv qui n’ont qu’un descripteur en commun :
n_client.Écrire un programme Python qui permet de fusionner les deux tables.
Indice
Charger les deux fichiers, en vérifiant leur séparateur, puis utiliser la fonction
fusionnerde l’exercice 8 avec la clé'n_client'.L’ordre a-t-il une importance lors de la fusion ?
Indice
Comparer
fusionner(clients, commandes, 'n_client')etfusionner(commandes, clients, 'n_client'): obtient-on les mêmes lignes, dans le même ordre ?Si vous avez fusionné à partir de la table
clients, vous avez peut-être remarqué que Mme Élodie Gaulin (numéro de client 895) est bien présente mais qu’il n’y a pas de commande correspondante. Pourquoi d’après vous ?Indice
Chercher le numéro 895 dans la colonne
n_clientde la tablecommandes: y figure-t-il ?De la même manière, aucune trace de la commande numéro 1324 du 01/02/2017 dans la table fusionnée. Pourquoi d’après vous ?
Indice
Chercher dans
commandesle numéro de client de la commande 1324, puis ce numéro dans la tableclients.
On remarquera aussi que Mme Neufville a fait deux commandes. D’où la nécessité de structurer correctement les données.