Atelier : nettoyer un CSV sale
Rendre un nettoyage rejouable et tracé.
Énoncé
Reprenez data/colis_bruts.csv de la leçon « Données fil rouge ». Écrivez clean.py qui produit data/colis_propres.csv et data/rapport_nettoyage.txt en un seul appel. Commencez par compter les lignes, les commande_id distincts, les poids manquants et les unités. Puis retirez les doublons exacts, convertissez tous les poids présents en kilogrammes et vérifiez qu'aucun poids présent n'est négatif ou nul.
Contraintes
Ne modifiez jamais le fichier brut. Conservez les valeurs de poids manquantes : la médiane doit être apprise uniquement sur le train, plus tard, dans un pipeline. Ne retirez aucune ligne pour son prix ou son retard. Le rapport doit donner les comptes avant/après, le nombre de conversions grammes → kilogrammes et les règles appliquées. Exécutez python clean.py deux fois : les deux sorties doivent être identiques.
Indices
drop_duplicates() enlève les copies exactes ; duplicated("commande_id") permet de vérifier l'unicité restante. Avec pd.to_numeric, les cases vides lues par read_csv restent manquantes. Utilisez un masque unite_poids == "g" pour diviser par 1 000. sort_values("commande_id") stabilise l'ordre de sortie.
Correction disponibleCherchez d’abord par vous-même.Voir la correction
Correction
Placez ce code dans clean.py, à côté du dossier data, puis lancez python clean.py :
from pathlib import Path
import pandas as pd
data = Path("data")
brut = pd.read_csv(data / "colis_bruts.csv")
assert set(brut["unite_poids"]) == {"g", "kg"}
nb_doublons = int(brut.duplicated().sum())
nb_manquants = int(brut["poids_valeur"].isna().sum())
propre = brut.drop_duplicates().copy()
assert propre["commande_id"].is_unique
propre["poids_kg"] = pd.to_numeric(propre["poids_valeur"])
en_grammes = propre["unite_poids"].eq("g")
propre.loc[en_grammes, "poids_kg"] /= 1000
assert (propre["poids_kg"].dropna() > 0).all()
propre = propre.drop(columns=["poids_valeur", "unite_poids"])
propre = propre.sort_values("commande_id").reset_index(drop=True)
propre.to_csv(data / "colis_propres.csv", index=False)
rapport = (
f"lignes brutes : {len(brut)}\n"
f"doublons exacts retirés : {nb_doublons}\n"
f"lignes propres : {len(propre)}\n"
f"poids manquants dans le brut : {nb_manquants}\n"
f"poids manquants conservés : {propre['poids_kg'].isna().sum()}\n"
f"poids convertis de g en kg : {en_grammes.sum()}\n"
"règles : doublons exacts retirés ; unités converties ; aucune imputation\n"
)
(data / "rapport_nettoyage.txt").write_text(rapport, encoding="utf-8")
print(rapport)
Sur le fichier fourni, il reste 320 commandes après retrait de 5 doublons. Le rapport ne doit annoncer aucune imputation. Une valeur manquante restera visible dans colis_propres.csv ; la préparer sans fuite sera la responsabilité du pipeline d'entraînement. Si le contrôle d'unicité échoue sur un autre jeu, examinez les lignes conflictuelles au lieu de garder arbitrairement la première.