etudiants = [
{"nom": "Alice", "classe": "A", "note": 14, "age": 20},
{"nom": "Bob", "classe": "B", "note": 8, "age": 22},
{"nom": "Charlie", "classe": "A", "note": 17, "age": 19},
{"nom": "Diana", "classe": "B", "note": 9, "age": 21},
{"nom": "Eve", "classe": "A", "note": 15, "age": 20},
{"nom": "Frank", "classe": "B", "note": 11, "age": 23},
{"nom": "Grace", "classe": "A", "note": 18, "age": 19},
]28 Extraction et traitement de volumes de données
Beaucoup de programmes passent leur temps à manipuler des collections de données : notes d’élèves, transactions, capteurs, articles… Ce chapitre rassemble les 4 opérations de base qu’on applique à des volumes de données, et montre comment les combiner pour produire des résultats utiles.
28.1 Les 4 opérations de base
| Opération | Rôle | Résultat |
|---|---|---|
| Filtrer | Garder un sous-ensemble selon un critère | Nouvelle collection (éventuellement plus petite) |
| Transformer | Appliquer une fonction à chaque élément | Nouvelle collection (même taille) |
| Agréger | Combiner tous les éléments en une valeur unique | Une valeur (somme, moyenne, max…) |
| Grouper | Répartir les éléments par catégorie | Dictionnaire par catégorie |
Vous verrez ces 4 opérations partout : Excel (filtres, formules, pivot), SQL (WHERE, SELECT, SUM, GROUP BY), Pandas… et bien sûr en Python.
Pour toutes les démos, on utilisera le même jeu de données :
28.2 Filtrer une collection
Filtrer = conserver uniquement les éléments qui vérifient une condition.
Avec une boucle explicite
etudiants = [
{"nom": "Alice", "classe": "A", "note": 14, "age": 20},
{"nom": "Bob", "classe": "B", "note": 8, "age": 22},
{"nom": "Charlie", "classe": "A", "note": 17, "age": 19},
{"nom": "Diana", "classe": "B", "note": 9, "age": 21},
{"nom": "Eve", "classe": "A", "note": 15, "age": 20},
{"nom": "Frank", "classe": "B", "note": 11, "age": 23},
{"nom": "Grace", "classe": "A", "note": 18, "age": 19},
]
# Filtrer : les étudiants ayant 10 ou plus
admis = []
for e in etudiants:
if e["note"] >= 10:
admis.append(e)
print(f"{len(admis)} étudiants admis")
for e in admis:
print(f" {e['nom']} : {e['note']}")5 étudiants admis
Alice : 14
Charlie : 17
Eve : 15
Frank : 11
Grace : 18
Avec une compréhension de liste (aperçu)
La même chose en une ligne avec une compréhension de liste (vue en Partie 3) :
etudiants = [
{"nom": "Alice", "classe": "A", "note": 14, "age": 20},
{"nom": "Bob", "classe": "B", "note": 8, "age": 22},
{"nom": "Charlie", "classe": "A", "note": 17, "age": 19},
{"nom": "Diana", "classe": "B", "note": 9, "age": 21},
{"nom": "Eve", "classe": "A", "note": 15, "age": 20},
{"nom": "Frank", "classe": "B", "note": 11, "age": 23},
{"nom": "Grace", "classe": "A", "note": 18, "age": 19},
]
admis = [e for e in etudiants if e["note"] >= 10]
print(f"{len(admis)} étudiants admis")5 étudiants admis
C’est plus court, plus lisible, et plus rapide. À ce stade, acceptez la syntaxe — la partie 3 la développera complètement.
Filtrage avec la fonction filter()
Python propose aussi la fonction native filter(). Moins utilisée aujourd’hui au profit des compréhensions, mais à reconnaître pour le TOSA.
etudiants = [
{"nom": "Alice", "note": 14},
{"nom": "Bob", "note": 8},
{"nom": "Eve", "note": 15},
]
admis = list(filter(lambda e: e["note"] >= 10, etudiants))
print(admis)[{'nom': 'Alice', 'note': 14}, {'nom': 'Eve', 'note': 15}]
filter(fonction, iterable) renvoie un itérateur — d’où le list(...) pour voir le résultat.
28.3 Transformer une collection
Transformer = appliquer une fonction à chaque élément pour produire une nouvelle collection.
Avec une boucle
notes = [12, 15, 9, 17, 11]
# Convertir en note sur 100
notes_100 = []
for n in notes:
notes_100.append(n * 5)
print(notes_100)[60, 75, 45, 85, 55]
Avec une compréhension
notes = [12, 15, 9, 17, 11]
notes_100 = [n * 5 for n in notes]
print(notes_100)[60, 75, 45, 85, 55]
Extraire un champ d’une liste de dicts (cas très fréquent)
etudiants = [
{"nom": "Alice", "note": 14},
{"nom": "Bob", "note": 8},
{"nom": "Eve", "note": 15},
]
# Ne garder que les noms
noms = [e["nom"] for e in etudiants]
print(noms)
# Ne garder que les notes
notes = [e["note"] for e in etudiants]
print(notes)['Alice', 'Bob', 'Eve']
[14, 8, 15]
Avec la fonction map()
Comme pour filter(), Python propose map(fonction, iterable). Moins utilisée aujourd’hui.
notes = [12, 15, 9, 17]
notes_100 = list(map(lambda n: n * 5, notes))
print(notes_100)[60, 75, 45, 85]
map / filter vs compréhensions
Les compréhensions sont aujourd’hui préférées parce que :
- Plus lisibles :
[n * 2 for n in notes]se lit mieux quelist(map(lambda n: n * 2, notes)). - Elles combinent map et filter en une expression :
[n * 2 for n in notes if n > 0].
map et filter restent utiles dans du code fonctionnel ou avec des fonctions existantes :
# Utile quand on a déjà la fonction à appliquer
notes = ["12", "15", "9"]
entiers = list(map(int, notes)) # convertit chaque str en int
print(entiers)[12, 15, 9]
28.4 Agréger une collection
Agréger = combiner tous les éléments en une valeur unique (somme, moyenne, max…).
Fonctions natives
Les agrégations simples ont leur raccourci natif :
notes = [12, 15, 9, 17, 11, 14]
print("Somme :", sum(notes))
print("Moyenne :", sum(notes) / len(notes))
print("Minimum :", min(notes))
print("Maximum :", max(notes))
print("Longueur :", len(notes))Somme : 78
Moyenne : 13.0
Minimum : 9
Maximum : 17
Longueur : 6
Comptage sous condition
Pour compter les éléments vérifiant une condition :
notes = [12, 15, 9, 17, 11, 8, 14]
# Avec une boucle
admis = 0
for n in notes:
if n >= 10:
admis += 1
print(f"{admis} notes >= 10")
# Avec sum (astuce : True vaut 1, False vaut 0 en Python)
admis = sum(1 for n in notes if n >= 10)
print(f"{admis} notes >= 10")
# Encore plus court
admis = sum(n >= 10 for n in notes) # somme des booléens !
print(f"{admis} notes >= 10")5 notes >= 10
5 notes >= 10
5 notes >= 10
Agréger avec une clé
min et max acceptent key= — utile pour trouver l’élément correspondant au min/max d’un critère.
etudiants = [
{"nom": "Alice", "note": 14},
{"nom": "Bob", "note": 8},
{"nom": "Charlie", "note": 17},
]
# Le meilleur étudiant (celui avec la note max)
meilleur = max(etudiants, key=lambda e: e["note"])
print("Meilleur :", meilleur)
# Le plus faible
faible = min(etudiants, key=lambda e: e["note"])
print("Plus faible :", faible)Meilleur : {'nom': 'Charlie', 'note': 17}
Plus faible : {'nom': 'Bob', 'note': 8}
28.5 Grouper par catégorie
Grouper = répartir les éléments dans un dictionnaire selon une clé catégorielle.
Manuellement
etudiants = [
{"nom": "Alice", "classe": "A", "note": 14},
{"nom": "Bob", "classe": "B", "note": 8},
{"nom": "Charlie", "classe": "A", "note": 17},
{"nom": "Diana", "classe": "B", "note": 9},
{"nom": "Eve", "classe": "A", "note": 15},
]
par_classe = {}
for e in etudiants:
c = e["classe"]
if c not in par_classe:
par_classe[c] = []
par_classe[c].append(e)
for classe, liste in par_classe.items():
print(f"Classe {classe} : {len(liste)} étudiants")
for e in liste:
print(f" - {e['nom']} ({e['note']})")Classe A : 3 étudiants
- Alice (14)
- Charlie (17)
- Eve (15)
Classe B : 2 étudiants
- Bob (8)
- Diana (9)
Avec dict.setdefault
On peut simplifier avec setdefault(clé, défaut) — renvoie la valeur existante, ou crée avec le défaut.
etudiants = [
{"nom": "Alice", "classe": "A", "note": 14},
{"nom": "Bob", "classe": "B", "note": 8},
{"nom": "Charlie", "classe": "A", "note": 17},
]
par_classe = {}
for e in etudiants:
par_classe.setdefault(e["classe"], []).append(e)
print(par_classe){'A': [{'nom': 'Alice', 'classe': 'A', 'note': 14}, {'nom': 'Charlie', 'classe': 'A', 'note': 17}], 'B': [{'nom': 'Bob', 'classe': 'B', 'note': 8}]}
Avec collections.defaultdict
La solution la plus élégante utilise un defaultdict :
from collections import defaultdict
etudiants = [
{"nom": "Alice", "classe": "A", "note": 14},
{"nom": "Bob", "classe": "B", "note": 8},
{"nom": "Charlie", "classe": "A", "note": 17},
]
par_classe = defaultdict(list) # valeur par défaut = liste vide
for e in etudiants:
par_classe[e["classe"]].append(e)
# Accès aux groupes
print(dict(par_classe)){'A': [{'nom': 'Alice', 'classe': 'A', 'note': 14}, {'nom': 'Charlie', 'classe': 'A', 'note': 17}], 'B': [{'nom': 'Bob', 'classe': 'B', 'note': 8}]}
defaultdict(list) crée automatiquement une liste vide la première fois qu’on accède à une clé nouvelle. Pas besoin de if ... not in.
Agréger par catégorie
Une fois groupé, on peut agréger chaque groupe :
from collections import defaultdict
etudiants = [
{"nom": "Alice", "classe": "A", "note": 14},
{"nom": "Bob", "classe": "B", "note": 8},
{"nom": "Charlie", "classe": "A", "note": 17},
{"nom": "Diana", "classe": "B", "note": 9},
{"nom": "Eve", "classe": "A", "note": 15},
]
# Grouper + calculer la moyenne par classe
notes_par_classe = defaultdict(list)
for e in etudiants:
notes_par_classe[e["classe"]].append(e["note"])
for classe, notes in notes_par_classe.items():
moyenne = sum(notes) / len(notes)
print(f"Classe {classe} : moyenne = {moyenne:.1f}")Classe A : moyenne = 15.3
Classe B : moyenne = 8.5
28.6 Combiner filtrer / transformer / agréger
La vraie puissance vient de la combinaison de ces opérations. Exemple concret : moyenne des notes des étudiants de la classe A qui ont au moins 10.
Version 1 — en trois étapes séparées
etudiants = [
{"nom": "Alice", "classe": "A", "note": 14},
{"nom": "Bob", "classe": "B", "note": 8},
{"nom": "Charlie", "classe": "A", "note": 17},
{"nom": "Diana", "classe": "B", "note": 9},
{"nom": "Eve", "classe": "A", "note": 15},
{"nom": "Grace", "classe": "A", "note": 8}, # pas admise
]
# 1. Filtrer : classe A et note >= 10
filtres = []
for e in etudiants:
if e["classe"] == "A" and e["note"] >= 10:
filtres.append(e)
# 2. Transformer : ne garder que les notes
notes = [e["note"] for e in filtres]
# 3. Agréger : moyenne
if notes:
moyenne = sum(notes) / len(notes)
print(f"Moyenne classe A (admis) : {moyenne:.2f}")Moyenne classe A (admis) : 15.33
Version 2 — en une compréhension
etudiants = [
{"nom": "Alice", "classe": "A", "note": 14},
{"nom": "Bob", "classe": "B", "note": 8},
{"nom": "Charlie", "classe": "A", "note": 17},
{"nom": "Diana", "classe": "B", "note": 9},
{"nom": "Eve", "classe": "A", "note": 15},
{"nom": "Grace", "classe": "A", "note": 8},
]
# Filtrer et extraire les notes en une ligne
notes = [e["note"] for e in etudiants if e["classe"] == "A" and e["note"] >= 10]
# Puis agréger
if notes:
moyenne = sum(notes) / len(notes)
print(f"Moyenne classe A (admis) : {moyenne:.2f}")Moyenne classe A (admis) : 15.33
Les compréhensions et leurs combinaisons sont le sujet central de la Partie 3. À ce stade, mémorisez le principe : filter-map-reduce est une chaîne naturelle qui s’exprime très bien en Python.
28.7 Lire des données depuis l’entrée standard
Dans beaucoup de scripts, les données viennent de l’utilisateur, d’un fichier, ou de l’entrée standard. Au niveau Opérationnel, on se concentre sur input().
Saisie d’une liste
# Saisir plusieurs valeurs séparées par des espaces
ligne = input("Entrez vos notes (séparées par des espaces) : ")
notes = [int(x) for x in ligne.split()]
print("Moyenne :", sum(notes) / len(notes))Saisie interactive jusqu’à un marqueur de fin
# Saisir des notes une par une, s'arrêter à chaîne vide
notes = []
while True:
saisie = input("Note (vide pour arrêter) : ").strip()
if not saisie:
break
notes.append(int(saisie))
print(f"{len(notes)} notes saisies, moyenne : {sum(notes)/len(notes):.2f}")Saisie d’un dict structuré
# Créer une fiche personne interactive
personne = {}
personne["nom"] = input("Nom : ").strip()
personne["age"] = int(input("Âge : "))
personne["ville"] = input("Ville : ").strip()
print(personne)🧩 Quiz 9.1 — Extraction de données
Question 1
Que renvoie ce code ?
notes = [12, 15, 9, 17, 11]
resultat = [n * 2 for n in notes if n >= 10]
print(resultat)[24, 30, 34, 22][24, 30, 18, 34, 22][12, 15, 17, 11]- Une erreur
a) [24, 30, 34, 22] — on filtre (>= 10) puis on transforme (* 2). Le 9 est exclu.
notes = [12, 15, 9, 17, 11]
print([n * 2 for n in notes if n >= 10])[24, 30, 34, 22]
Question 2
Que renvoie sum(n > 10 for n in [5, 15, 20, 8]) ?
43235- Une erreur
b) 2 — n > 10 renvoie True (= 1) ou False (= 0). La somme des booléens compte les éléments vérifiant la condition. Ici : 15 > 10 et 20 > 10 → 2.
print(sum(n > 10 for n in [5, 15, 20, 8]))2
Question 3
Quelle fonction renvoie l’élément maximum selon un critère ?
max(liste, reverse=True)max(liste, key=...)sorted(liste)[-1]max(liste).sort()
b) max(liste, key=...) — le paramètre key sert à spécifier le critère de comparaison. Très utile pour des listes d’objets complexes.
etudiants = [{"nom": "Alice", "note": 14}, {"nom": "Bob", "note": 17}]
print(max(etudiants, key=lambda e: e["note"])){'nom': 'Bob', 'note': 17}
Question 4
Quelle structure est la plus adaptée pour grouper des données par catégorie ?
listtuplesetdict(oudefaultdict)
d) dict — chaque catégorie est une clé, chaque valeur est la liste des éléments. defaultdict(list) simplifie la création automatique de listes vides.
from collections import defaultdict
groupes = defaultdict(list)
for x in [("A", 1), ("B", 2), ("A", 3)]:
groupes[x[0]].append(x[1])
print(dict(groupes)){'A': [1, 3], 'B': [2]}
Question 5
Que renvoie ce code ?
etudiants = [{"nom": "A", "note": 12}, {"nom": "B", "note": 18}]
noms = [e["nom"] for e in etudiants]
print(noms)["A", "B"]["A", "B", 12, 18]{"A", "B"}- Une erreur
a) ["A", "B"] — la compréhension extrait le champ "nom" de chaque dict. Pattern très courant.
etudiants = [{"nom": "A", "note": 12}, {"nom": "B", "note": 18}]
print([e["nom"] for e in etudiants])['A', 'B']
Question 6
Quelle est la différence entre filter() et une compréhension [x for x in l if ...] ?
filterest plus rapidefilterrenvoie un itérateur, la compréhension renvoie une listefilterne fonctionne qu’avec des nombres- Il n’y a pas de différence
b) filter renvoie un itérateur — il faut list(...) pour obtenir une vraie liste. La compréhension renvoie directement une liste.
# filter renvoie un itérateur
r = filter(lambda n: n > 0, [-1, 2, 3])
print(type(r))
print(list(r))
# compréhension renvoie une liste
r = [n for n in [-1, 2, 3] if n > 0]
print(type(r))
print(r)<class 'filter'>
[2, 3]
<class 'list'>
[2, 3]
✏️ Exercice 9.1 — Filtrer et compter
À partir du jeu de données initial, comptez combien d’étudiants :
- Ont la moyenne (note ≥ 10).
- Sont dans la classe A.
- Ont la moyenne ET sont dans la classe B.
etudiants = [
{"nom": "Alice", "classe": "A", "note": 14},
{"nom": "Bob", "classe": "B", "note": 8},
{"nom": "Charlie", "classe": "A", "note": 17},
{"nom": "Diana", "classe": "B", "note": 9},
{"nom": "Eve", "classe": "A", "note": 15},
{"nom": "Frank", "classe": "B", "note": 11},
{"nom": "Grace", "classe": "A", "note": 18},
]
# 1. Ayant la moyenne
...
# 2. Dans la classe A
...
# 3. Moyenne ET classe B
...etudiants = [
{"nom": "Alice", "classe": "A", "note": 14},
{"nom": "Bob", "classe": "B", "note": 8},
{"nom": "Charlie", "classe": "A", "note": 17},
{"nom": "Diana", "classe": "B", "note": 9},
{"nom": "Eve", "classe": "A", "note": 15},
{"nom": "Frank", "classe": "B", "note": 11},
{"nom": "Grace", "classe": "A", "note": 18},
]
# 1. Admis
admis = sum(e["note"] >= 10 for e in etudiants)
print("Admis :", admis)
# 2. Classe A
classe_a = sum(e["classe"] == "A" for e in etudiants)
print("Classe A :", classe_a)
# 3. Admis ET classe B
admis_b = sum(e["note"] >= 10 and e["classe"] == "B" for e in etudiants)
print("Admis en B :", admis_b)Admis : 5
Classe A : 4
Admis en B : 1
✏️ Exercice 9.2 — Transformation d’une liste
Soit la liste mots = ["Alice", " BOB ", " charlie", "DIANA"]. Produisez une nouvelle liste contenant ces mots nettoyés (sans espaces de début/fin) et normalisés (première lettre en majuscule, reste en minuscule).
Exemple de résultat : ["Alice", "Bob", "Charlie", "Diana"].
mots = ["Alice", " BOB ", " charlie", "DIANA"]
# Nettoyer et normaliser
...mots = ["Alice", " BOB ", " charlie", "DIANA"]
# Version boucle
normalises = []
for m in mots:
normalises.append(m.strip().capitalize())
print(normalises)
# Version compréhension (plus idiomatique)
normalises = [m.strip().capitalize() for m in mots]
print(normalises)['Alice', 'Bob', 'Charlie', 'Diana']
['Alice', 'Bob', 'Charlie', 'Diana']
.capitalize() met la première lettre en majuscule et le reste en minuscule — exactement ce qu’il faut ici.
✏️ Exercice 9.3 — Agréger par catégorie
À partir du jeu de données des étudiants, produisez un dictionnaire qui associe chaque classe à :
- Le nombre d’étudiants de la classe.
- La moyenne des notes de la classe.
- La meilleure note de la classe.
etudiants = [
{"nom": "Alice", "classe": "A", "note": 14},
{"nom": "Bob", "classe": "B", "note": 8},
{"nom": "Charlie", "classe": "A", "note": 17},
{"nom": "Diana", "classe": "B", "note": 9},
{"nom": "Eve", "classe": "A", "note": 15},
{"nom": "Frank", "classe": "B", "note": 11},
{"nom": "Grace", "classe": "A", "note": 18},
]
# Produire un dict de la forme :
# {"A": {"nb": 4, "moyenne": 16.0, "max": 18}, "B": {...}}from collections import defaultdict
etudiants = [
{"nom": "Alice", "classe": "A", "note": 14},
{"nom": "Bob", "classe": "B", "note": 8},
{"nom": "Charlie", "classe": "A", "note": 17},
{"nom": "Diana", "classe": "B", "note": 9},
{"nom": "Eve", "classe": "A", "note": 15},
{"nom": "Frank", "classe": "B", "note": 11},
{"nom": "Grace", "classe": "A", "note": 18},
]
# Étape 1 : grouper les notes par classe
notes_par_classe = defaultdict(list)
for e in etudiants:
notes_par_classe[e["classe"]].append(e["note"])
# Étape 2 : calculer les agrégats
stats = {}
for classe, notes in notes_par_classe.items():
stats[classe] = {
"nb": len(notes),
"moyenne": round(sum(notes) / len(notes), 2),
"max": max(notes),
}
# Affichage
for classe, infos in sorted(stats.items()):
print(f"Classe {classe} : {infos}")Classe A : {'nb': 4, 'moyenne': 16.0, 'max': 18}
Classe B : {'nb': 3, 'moyenne': 9.33, 'max': 11}
✏️ Exercice 9.4 — Pipeline complet
Produisez la liste des prénoms des étudiants de la classe A ayant une note strictement supérieure à 15, triés par note décroissante.
etudiants = [
{"nom": "Alice", "classe": "A", "note": 14},
{"nom": "Bob", "classe": "B", "note": 8},
{"nom": "Charlie", "classe": "A", "note": 17},
{"nom": "Diana", "classe": "B", "note": 9},
{"nom": "Eve", "classe": "A", "note": 15},
{"nom": "Frank", "classe": "B", "note": 11},
{"nom": "Grace", "classe": "A", "note": 18},
]
# Filtrer → trier → extraireetudiants = [
{"nom": "Alice", "classe": "A", "note": 14},
{"nom": "Bob", "classe": "B", "note": 8},
{"nom": "Charlie", "classe": "A", "note": 17},
{"nom": "Diana", "classe": "B", "note": 9},
{"nom": "Eve", "classe": "A", "note": 15},
{"nom": "Frank", "classe": "B", "note": 11},
{"nom": "Grace", "classe": "A", "note": 18},
]
# 1. Filtrer
candidats = [e for e in etudiants if e["classe"] == "A" and e["note"] > 15]
# 2. Trier par note décroissante
candidats.sort(key=lambda e: e["note"], reverse=True)
# 3. Extraire les noms
noms = [e["nom"] for e in candidats]
print("Meilleurs de classe A (note > 15) :", noms)Meilleurs de classe A (note > 15) : ['Grace', 'Charlie']
etudiants = [
{"nom": "Alice", "classe": "A", "note": 14},
{"nom": "Charlie", "classe": "A", "note": 17},
{"nom": "Eve", "classe": "A", "note": 15},
{"nom": "Grace", "classe": "A", "note": 18},
{"nom": "Bob", "classe": "B", "note": 8},
]
noms = [
e["nom"]
for e in sorted(etudiants, key=lambda e: e["note"], reverse=True)
if e["classe"] == "A" and e["note"] > 15
]
print(noms)['Grace', 'Charlie']
Ces enchaînements sont très fréquents en data. Maîtrisez-les.
À retenir
- 4 opérations fondamentales : filtrer, transformer, agréger, grouper.
- Filtrer avec une compréhension :
[x for x in liste if cond]. - Transformer avec une compréhension :
[f(x) for x in liste]. - Agréger :
sum,min,max,len,sum(True/False)pour compter. min/maxaveckey=pour trouver l’élément optimal selon un critère.- Grouper avec
defaultdict(list)oudict.setdefault(k, []).append(...). - Les chaînes filtrer → trier → transformer sont le pain quotidien du traitement de données.
filter/mapexistent mais les compréhensions sont plus Pythoniques.