Travail 3 sur 3 · livrable complet, code compris
Enrichissement d'un catalogue de 119 lignes
Un export fournisseur volontairement cassé, traité de bout en bout. Le script est fourni, il n'a aucune dépendance et il est déterministe : relancez-le et vous retrouverez les chiffres du rapport, à l'octet près.
Les fichiers, tels qu'ils sont livrés
- catalogue-source.csv l'export d'entrée, 119 lignes 13 ko
- catalogue-enrichi.csv la sortie normalisée, 110 références, 16 colonnes 20 ko
- a-decider.csv les 90 lignes que nous refusons de deviner 10 ko
- enrichir.py le script de traitement, sans dépendance 19 ko
- generer-source.py le générateur de la source, graine fixe 5 ko
- rapport-enrichissement.md le rapport de remplissage 4 ko
Rapport d'enrichissement de catalogue
Source : catalogue-source.csv — 119 lignes, 11 colonnes Sortie : catalogue-enrichi.csv — 110 références uniques, 16 colonnes À trancher par un humain : a-decider.csv — 90 lignes
1. Taux de remplissage, avant et après
| Champ | Avant | Après | Écart |
|---|---|---|---|
| libellé | 97.5 % | 100.0 % | +2.5 pt |
| marque | 100.0 % | 100.0 % | +0.0 pt |
| catégorie | 100.0 % | 100.0 % | +0.0 pt |
| prix | 100.0 % | 100.0 % | +0.0 pt |
| poids | 89.9 % | 90.0 % | +0.1 pt |
| couleur | 83.2 % | 82.7 % | -0.5 pt |
| matière | 70.6 % | 68.2 % | -2.4 pt |
| GTIN valide | 47.9 % | 48.2 % | +0.3 pt |
| attribut métier structuré | 0,0 % | 100.0 % | +100.0 pt |
| chemin de taxonomie | 0,0 % | 100.0 % | +100.0 pt |
| slug d'URL | 0,0 % | 100,0 % | +100,0 pt |
Références complètes sur tous les champs obligatoires : 54/110 (49.1 %).
Le champ « attribut métier » est le vrai apport : le volume d'un sac, la température de confort d'un duvet ou le flux d'une frontale étaient noyés dans le libellé, en texte libre. Ils sont désormais des colonnes exploitables — donc filtrables en boutique, et lisibles par un flux Google Shopping.
2. Corrections appliquées
| Correction | Occurrences |
|---|---|
| libellé nettoyé (HTML, espaces, casse, unités recollées) | 99 |
| catégorie libre rattachée à la taxonomie | 96 |
| poids converti en grammes (kg, g, « grammes ») | 74 |
| casse de marque normalisée | 71 |
| prix converti en décimal (formats €, EUR, virgule, espaces) | 62 |
| GTIN invalide écarté | 37 |
| couleur normalisée | 35 |
| matière normalisée | 35 |
| stock négatif ramené à 0 | 29 |
| stock non numérique ramené à 0 | 23 |
| attribut « temperature_c » extrait du libellé | 17 |
| attribut « volume_l » extrait du libellé | 17 |
| attribut « flux_lm » extrait du libellé | 17 |
| attribut « longueur_cm » extrait du libellé | 16 |
| attribut « places » extrait du libellé | 13 |
| attribut « epaisseur_cm » extrait du libellé | 13 |
| attribut « poids_annonce_g » extrait du libellé | 12 |
| attribut « contenance_ml » extrait du libellé | 11 |
| doublon de référence fusionné | 6 |
| libellé vide — ligne écartée | 3 |
Total : 686 corrections déterministes.
3. Ce que la machine n'a pas tranché
90 lignes sont remontées dans a-decider.csv.
| Motif | Lignes |
|---|---|
| matière incohérente avec la catégorie | 44 |
| GTIN invalide (clé de contrôle ou longueur) | 37 |
| doublon avec deux prix différents | 6 |
| libellé vide | 3 |
Aucune de ces valeurs n'a été devinée. Un pipeline qui invente un prix manquant ou rattache une catégorie inconnue « au plus proche » ne produit pas un catalogue complet, il produit un catalogue faux — et l'erreur devient invisible. Le temps humain se concentre ici, et nulle part ailleurs.
4. Contrôles exécutés
| Contrôle | Règle |
|---|---|
| Doublon de référence | fusion des deux lignes, la valeur renseignée l'emporte sur le vide ; prix divergents remontés |
| GTIN-13 | longueur 13 + clé de contrôle modulo 10 recalculée ; les codes tout à zéro sont rejetés |
| Prix | 12,90 €, 12.90EUR, 12.90 → 12.90 ; zéro et négatif rejetés |
| Poids | 780g, 0,78 kg, 780 grammes → 780 |
| Libellé | balises HTML retirées, espaces insécables et multiples réduits, capitales corrigées, unités recollées |
| Catégorie | rattachement à une taxonomie fermée + chemin Google Shopping ; hors référentiel = remonté |
| Matière | cohérence avec la catégorie (un duvet en acier inoxydable est une erreur de saisie) |
| Stock | valeurs négatives et non numériques ramenées à 0 |
| Slug | translittération sans accent, minuscules, tirets |
5. Reproductibilité
python3 generer-source.py # régénère la source, graine fixe
python3 enrichir.py # régénère les trois fichiers de sortie
Le traitement est déterministe : deux exécutions sur la même source donnent le même octet. C'est ce qui rend le rapport opposable.
Pièce 3 — Nettoyage et enrichissement d'un catalogue produit (119 lignes)
Livrable complet et exécutable. Tout ce qui est affiché ici a été calculé, pas rédigé.
Reproduire en deux commandes
python3 generer-source.py # régénère le catalogue fournisseur sale (graine fixe)
python3 enrichir.py # régénère les trois fichiers de sortie
Le traitement est déterministe : deux exécutions produisent des fichiers identiques à l'octet près. C'est ce qui rend le rapport opposable en cas de désaccord.
Contenu
| Fichier | Rôle |
|---|---|
catalogue-source.csv | Entrée. Export fournisseur réaliste, 119 lignes, 11 colonnes, avec ses défauts |
generer-source.py | Génère la source. Fourni pour que le résultat soit vérifiable, pas livré au client |
enrichir.py | Le pipeline. 380 lignes commentées, aucune dépendance externe |
catalogue-enrichi.csv | Sortie 1. 110 références uniques, 16 colonnes |
a-decider.csv | Sortie 2. 90 lignes que la machine refuse de trancher seule |
rapport-enrichissement.md | Sortie 3. Taux de remplissage avant/après, journal des corrections |
Résultat mesuré
| Lignes en entrée | 119 |
| Références uniques en sortie | 110 |
| Corrections déterministes appliquées | 686 |
| Lignes remontées pour décision humaine | 90 |
| Attribut métier structuré | 0 % → 100 % |
| Chemin de taxonomie Google Shopping | 0 % → 100 % |
| Slug d'URL | 0 % → 100 % |
| Doublons de référence fusionnés | 6 |
| GTIN invalides détectés et écartés | 37 |
| Références complètes sur tous les champs obligatoires | 49,1 % |
Ce que le pipeline corrige tout seul
Balises HTML et espaces insécables dans les libellés · capitales intempestives · unités recollées (30L → 30 L) · casse des marques (kerhan, KERHAN, Kerhan → Kerhan) · catégories en texte libre rattachées à une taxonomie fermée avec chemin Google Shopping · prix en 12,90 € / 12.90EUR / 12.90 convertis en décimal · poids en 780g / 0,78 kg / 780 grammes convertis en grammes · clé de contrôle GTIN-13 recalculée modulo 10 · stocks négatifs et non numériques ramenés à 0 · doublons de référence fusionnés champ par champ · slug translittéré.
Et l'enrichissement proprement dit : le volume d'un sac, la température de confort d'un duvet, le flux d'une frontale, la contenance d'une gourde étaient noyés dans le libellé en texte libre. Ils deviennent des colonnes. C'est ce qui rend un catalogue filtrable en boutique et lisible par un flux Google Shopping — et c'est la seule partie du travail qui change le chiffre d'affaires plutôt que la propreté du fichier.
Ce que le pipeline refuse de faire
Il ne devine jamais. 90 lignes partent dans a-decider.csv avec le motif, la valeur source et l'action attendue :
| Motif | Lignes |
|---|---|
| Matière incohérente avec la catégorie (un duvet en acier inoxydable) | 44 |
| GTIN invalide — clé de contrôle ou longueur | 37 |
| Doublon avec deux prix différents | 6 |
| Libellé vide | 3 |
C'est le point qui distingue cette prestation d'un « nettoyage de données à 15 € les 1 000 lignes ». Un script qui complète un prix manquant par la moyenne de la catégorie, ou qui rattache une catégorie inconnue « à la plus proche », ne produit pas un catalogue complet : il produit un catalogue faux dont l'erreur est devenue invisible. Le taux de complétude de 49,1 % est le chiffre honnête, et il est plus utile qu'un 100 % fabriqué.
C'est aussi là que se loge le temps humain facturé : les 90 arbitrages, pas le nettoyage.
Pourquoi c'est vérifiable, et pourquoi ça compte
Les critères d'acceptation sont des nombres convenus avant la commande : taux de remplissage par colonne, nombre de doublons résiduels (0), nombre de GTIN invalides restants dans le fichier de sortie (0), nombre de catégories hors taxonomie (0). Le client peut relancer le script sur son propre poste et retrouver exactement les mêmes chiffres.
Aucune de ces mesures ne dépend du goût de qui que ce soit. C'est la différence entre une prestation qu'on discute et une prestation qu'on constate.
Honnêteté sur ce lot
Le catalogue est synthétique : il a été généré pour la démonstration, à partir des défauts réellement rencontrés dans les exports fournisseurs (unités mélangées, deux formats de prix, doublons de SKU, catégories libres, GTIN manquants ou à clé fausse). Aucune donnée client réelle n'est utilisée, et aucune donnée personnelle n'apparaît nulle part — ce catalogue ne contient que des produits.