Nettoyer les données
Les vraies données sont sales
Le fichier de janvier à mars était parfait. Celui d'avril, tapé à la main par le neveu de Mama Brigitte un soir de fatigue, l'est beaucoup moins. Ouvre-le :
date,produit,quantite,prix_unitaire,vendeur
2026-04-01,riz,2,1200,Awa
2026-04-01, Huile ,1,1500,Paul
2026-04-02,SAVON,4,500,Mireille
2026-04-03,riz,,1200,Paul
2026-04-03,sucre,3,900,Awa
2026-04-04,riz,1,1 200,Mireille
2026-04-05,lait,deux,650,Paul
2026-04-05,huile,2,1500
2026-04-06,Spaghetti,5,400,Awa
2026-04-07, riz,10,1200, Paul
Compte les problèmes :
| Ligne | Problème | Que faire ? |
|---|---|---|
Huile |
espaces autour, majuscule | corriger : "huile" |
| (vide) | ligne vide | ignorer |
SAVON |
majuscules | corriger : "savon" |
riz,,1200 |
quantité manquante | rejeter : on ne peut pas deviner |
1 200 |
espace dans le nombre | corriger : 1200 |
deux |
nombre écrit en lettres | rejeter |
huile,2,1500 |
il manque le vendeur | rejeter |
riz, Paul |
espaces | corriger |
Avec la fonction lire_ventes du cours 1, ce fichier ferait planter le programme dès la ligne vide. Et même sans plantage, "Huile", " Huile " et "huile" seraient comptés comme trois produits différents.
Nettoyer un texte
Tu connais déjà les outils :
| Méthode | Effet | Exemple |
|---|---|---|
.strip() |
enlève les espaces au début et à la fin | " Huile ".strip() vaut "Huile" |
.lower() |
met tout en minuscules | "SAVON".lower() vaut "savon" |
.replace(a, b) |
remplace chaque a par b |
"1 200".replace(" ", "") vaut "1200" |
On peut les enchaîner : " Huile ".strip().lower() vaut "huile". Python applique .strip() d'abord, puis .lower() au résultat.
Exercice : Deux petites fonctions de nettoyage
Écris :
nettoyer_texte(texte), qui renvoie le texte sans espaces autour et en minuscules ;nettoyer_nombre(texte), qui enlève tous les espaces (y compris au milieu) et renvoie le nombre entier correspondant.
Voir une solution
def nettoyer_texte(texte):
"""Enlève les espaces autour et met en minuscules."""
return texte.strip().lower()
def nettoyer_nombre(texte):
"""Enlève tous les espaces et renvoie le nombre entier."""
return int(texte.replace(" ", ""))Dans l'appli, ton code est exécuté et corrigé automatiquement. Faire l'exercice
Quand la conversion échoue : try et except
Que fait nettoyer_nombre("deux") ? Python essaie int("deux") et s'arrête :
ValueError: invalid literal for int() with base 10: 'deux'
Même chose avec "", la quantité vide. Pour un programme qui lit des milliers de lignes, s'arrêter à la première faute n'est pas acceptable. Il faut pouvoir dire : « essaie de convertir ; si ça rate, fais autre chose ».
texte = "deux"
try:
quantite = int(texte)
print("Conversion réussie")
except ValueError:
quantite = None
print("Ce n'est pas un nombre :", texte)
Ici, int(texte) échoue : la ligne print("Conversion réussie") n'est jamais exécutée, Python passe directement dans except.
Voir try et except en action
Lance, puis ajoute tes propres textes dans la liste.
essais = ["12", " 7 ", "1 200", "", "deux", "3.5"]
for texte in essais:
try:
nombre = int(texte.replace(" ", ""))
print(f"'{texte}' devient {nombre}")
except ValueError:
print(f"'{texte}' n'est pas un nombre entier")
Exercice : Convertir sans planter
Écris convertir(texte) qui enlève tous les espaces du texte, puis renvoie le nombre entier correspondant. Si le texte ne contient pas un nombre entier valable, la fonction renvoie None au lieu de planter.
Voir une solution
def convertir(texte):
"""Renvoie le nombre entier écrit dans texte, ou None s'il n'y en a pas."""
try:
return int(texte.replace(" ", ""))
except ValueError:
return NoneDans l'appli, ton code est exécuté et corrigé automatiquement. Faire l'exercice
Le plan de la lecture propre
On a tous les outils. Voici ce que fera la nouvelle fonction de lecture, pour chaque ligne après l'en-tête :
- Ligne vide (seulement des espaces ou rien) : on l'ignore avec
continue. - On découpe aux virgules. S'il n'y a pas exactement 5 morceaux : on rejette la ligne.
- On convertit la quantité et le prix avec
convertir. Si l'un des deux vautNone: on rejette. - Sinon, on nettoie le produit (
nettoyer_texte), la date et le vendeur (.strip()), et on ajoute la vente.
La fonction renverra deux listes : les ventes valables, et les lignes rejetées, pour pouvoir les montrer à Mama Brigitte.
Pour le vendeur, on garde les majuscules ("Paul") : un nom propre s'écrit avec sa majuscule. On enlève juste les espaces.
Exercice : La brique de lecture propre
Les deux fonctions de nettoyage sont données. Complète lire_ventes_propres(nom_fichier) en suivant le plan, puis observe le résultat sur le fichier d'avril.
Voir une solution
def nettoyer_texte(texte):
"""Enlève les espaces autour et met en minuscules."""
return texte.strip().lower()
def convertir(texte):
"""Renvoie le nombre entier écrit dans texte, ou None s'il n'y en a pas."""
try:
return int(texte.replace(" ", ""))
except ValueError:
return None
def lire_ventes_propres(nom_fichier):
"""Lit un CSV de ventes, nettoie chaque ligne et met de côté les lignes invalides."""
with open(nom_fichier, encoding="utf-8") as f:
lignes = f.read().splitlines()
ventes = []
rejetees = []
for ligne in lignes[1:]:
if ligne.strip() == "":
continue
morceaux = ligne.split(",")
if len(morceaux) != 5:
rejetees.append(ligne)
continue
date, produit, quantite, prix, vendeur = morceaux
quantite = convertir(quantite)
prix = convertir(prix)
if quantite is None or prix is None:
rejetees.append(ligne)
continue
ventes.append({
"date": date.strip(),
"produit": nettoyer_texte(produit),
"quantite": quantite,
"prix": prix,
"vendeur": vendeur.strip(),
})
return ventes, rejetees
ventes, rejetees = lire_ventes_propres("ventes_brutes.csv")
print(len(ventes), "ventes valables")
print(len(rejetees), "lignes rejetées :")
for ligne in rejetees:
print(" ", ligne)Dans l'appli, ton code est exécuté et corrigé automatiquement. Faire l'exercice
Exercice : Défi : le taux de rejet
Un bon analyste dit toujours quelle part des données il a dû écarter. Si 3 lignes sur 10 sont rejetées, le résultat est beaucoup moins fiable que si c'est 3 sur 10 000.
La lecture propre est donnée. Calcule dans taux le pourcentage de lignes rejetées parmi les lignes non vides (valables + rejetées), arrondi à l'entier. Affiche Lignes rejetées : 30 %.
Voir une solution
def nettoyer_texte(texte):
"""Enlève les espaces autour et met en minuscules."""
return texte.strip().lower()
def convertir(texte):
"""Renvoie le nombre entier écrit dans texte, ou None s'il n'y en a pas."""
try:
return int(texte.replace(" ", ""))
except ValueError:
return None
def lire_ventes_propres(nom_fichier):
"""Lit un CSV de ventes, nettoie chaque ligne et met de côté les lignes invalides."""
with open(nom_fichier, encoding="utf-8") as f:
lignes = f.read().splitlines()
ventes = []
rejetees = []
for ligne in lignes[1:]:
if ligne.strip() == "":
continue
morceaux = ligne.split(",")
if len(morceaux) != 5:
rejetees.append(ligne)
continue
date, produit, quantite, prix, vendeur = morceaux
quantite = convertir(quantite)
prix = convertir(prix)
if quantite is None or prix is None:
rejetees.append(ligne)
continue
ventes.append({
"date": date.strip(),
"produit": nettoyer_texte(produit),
"quantite": quantite,
"prix": prix,
"vendeur": vendeur.strip(),
})
return ventes, rejetees
ventes, rejetees = lire_ventes_propres("ventes_brutes.csv")
taux = round(len(rejetees) / (len(ventes) + len(rejetees)) * 100)
print(f"Lignes rejetées : {taux} %")Dans l'appli, ton code est exécuté et corrigé automatiquement. Faire l'exercice
Teste-toi
Qu'affiche ce code ?
python try: n = int("abc") print("A") except ValueError: print("B") print("C")
- A puis C
- B puis C (bonne réponse)
- A, B puis C
- B seulement
Pourquoi éviter except: sans nom d'exception ?
- C'est une erreur de syntaxe
- Il attrape aussi les vraies fautes du programme, qui deviennent invisibles (bonne réponse)
- Il ralentit beaucoup le programme
- Il n'attrape aucune erreur