Aller au contenu
English

Profiler avant de modifier

  • Leçon 10
  • 55 min
  • Module 4 : Nettoyer et transformer les données

Ce que vous saurez faire

Mesurez les problèmes dans les données avant de modifier une valeur. Si vous nettoyez d’abord, vous ne pourrez pas dire ensuite ce que vous avez changé, combien de lignes cela touchait, ni pourquoi.

Carnet JupyterFaites cette leçon dans un carnet JupyterColab · Kaggle · GitHub · en anglais

Le carnet (notebook) Jupyter contient toutes les requêtes, tâches et vérifications de cette leçon, avec les instructions. Ses cellules de préparation installent pandas, créent la base de données et produisent l’extrait du module 3. Il ne nécessite donc aucune préparation locale. Lisez les explications ici et exécutez le code là-bas.

Le carnet est en anglais. Colab et Kaggle ouvrent votre propre copie. Il faut un compte Google ou Kaggle gratuit. Vous êtes bloqué ? Consultez le carnet de solution.

Avant de commencerCe qu’il faut savoir et avoir sous la mainEnviron 55 minutes

Ce que vous devez savoir

Ce qu’il vous faut sur votre ordinateur (seulement pour le parcours local; le carnet et les encadrés de cette page n’en ont pas besoin)

  • Le dossier ~/projects/ticket-data avec larkfield.db et q.py. Vous l’avez créé dans Préparer une base de données d’exercice : créer la base de données. Si la base de données manque ou a changé, réinitialisez-la avec python3 get_data.py --reset.
  • L’extrait data/extract/tickets.csv (1 416 lignes), produit par python3 scripts/extract.py (sous Windows, python scripts/extract.py). Vous l’avez créé dans Une extraction reproductible : exercice guidé. Si le script manque ou ne fonctionne plus, récupérez les scripts terminés du cours. Copiez scripts/extract.py et les deux fichiers de queries/ dans votre projet, puis exécutez le script à nouveau.
  • Un terminal ouvert dans ce dossier et une connexion Internet, une seule fois, pour installer pandas. Aucun compte ni paiement n’est nécessaire.
  • Les requêtes enregistrées de ce module vont dans queries/, avec une numérotation commençant par 41-.

Testé sous macOS avec Python 3.14.6 et pandas 3.0.6. Les encadrés du navigateur utilisent SQLite 3.49.1. Les étapes Windows ne sont pas testées. Le carnet a été testé dans Jupyter.

Larkfield est une boutique en ligne fictive de produits pour la maison et le jardin. Son service de soutien veut un modèle qui prédit, à l’arrivée d’un billet de soutien, s’il nécessitera un agent expérimenté. Dans les modules 1 à 3, vous avez interrogé l’exportation du service de soutien et enregistré un extrait reproductible. Dans ce module, Mei, l’ingénieure de données, nettoie cet extrait. Les données sont inventées pour ce cours; elles ne contiennent aucune personne réelle.

Le module comporte trois étapes, une par leçon :

  1. Profiler les données : trouver et compter chaque problème. Ne rien changer. (Cette leçon.)
  2. Charger les données dans Python avec les bons types, puis les joindre et les convertir en étapes nommées. (Leçon 2.)
  3. Décider quoi faire avec chaque problème, conserver les valeurs originales et rendre compte de chaque ligne. (Leçon 3.)

Un profil est une courte description d’un jeu de données, colonne par colonne. Il indique combien de valeurs manquent, quelles valeurs apparaissent, ainsi que les valeurs minimale et maximale. Vous le créez avant toute modification, pour deux raisons. D’abord, il vous montre les problèmes. Ensuite, il représente l’état « avant ». Après le nettoyage, vous comparez le résultat avec cet état.

Regardez d’abord cinq billets inventés. Chaque ligne contient un problème qui ne provoque pas d’erreur :

ticket_id channel order_value word_count created_at Problème
T-1 email 42.50 80 2026-03-02 aucun
T-2 Email NULL 45 2026-03-02 une deuxième graphie de email (courriel); une valeur manquante
T-3 chat -1 120 2026-03-03 -1 n’est pas un montant : c’est un code pour « inconnu »
T-3 chat -1 120 2026-03-03 la même ligne deux fois
T-4 web_form 4250 31000 2036-03-04 des cents, pas des dollars; un message très long; une année dans le futur

Une requête sur cette table s’exécute sans erreur. AVG(order_value) renvoie un nombre. Mais ce nombre est faux, et rien ne vous l’indique. Un profil pose cinq questions, et chaque question détecte un type de problème :

Question Type de problème Dans les cinq billets
Quelles valeurs manquent, et que signifie chaque valeur manquante? valeurs manquantes T-2 n’a pas de order_value
Une ligne ou une clé apparaît-elle plus d’une fois? doublons T-3 deux fois
Toutes les valeurs figurent-elles dans la liste des valeurs permises? catégories invalides Email à côté de email
Toutes les valeurs utilisent-elles la même unité? unités incohérentes 4 250 cents à côté de 42,50 dollars
Les valeurs sont-elles dans une plage raisonnable? plages suspectes 31 000 mots, l’année 2036, -1

Le profil ne fait que trouver et compter. Les décisions viennent à la leçon 3. Certaines décisions nécessitent une personne qui connaît les activités de l’entreprise. Chez Larkfield, cette personne est Grace, la responsable du soutien.

Mei profile l’exportation complète dans larkfield.db (1 417 lignes de billets), pas seulement l’extrait. L’extrait a exclu une ligne. Le profil doit aussi montrer cette ligne.

COUNT(*) compte les lignes. COUNT(column) compte les valeurs qui ne sont pas NULL. (NULL est le marqueur SQL qui signifie « aucune valeur ici ».) Donc, COUNT(*) - COUNT(column) donne le nombre de valeurs manquantes. Faites d’abord une prédiction : quelle colonne contient le plus de NULL?

Exécutez du SQL dans votre navigateur

Essayez : compter les valeurs manquantes

Exécutez la requête. Vous devriez voir 1 ligne : 1 417 lignes, puis 12, 38, 188, 0 et 12 valeurs manquantes.

Quatre colonnes contiennent des valeurs manquantes. Un compte seul ne suffit pas : le profil doit aussi indiquer ce que chaque NULL signifie. Mei interroge Grace sur chacune :

Colonne Lignes NULL Ce que NULL signifie (Grace)
customer_id 12 Un achat sans compte. Le client n’a pas de compte.
channel 38 Le service de soutien n’a pas enregistré le canal. Il est inconnu.
order_value 188 ? Mei vérifie ce cas dans le prochain encadré.
closed_at 12 Le billet est encore ouvert.

Exécutez du SQL dans votre navigateur

À vous : quels billets n'ont pas de montant de commande?

Écrivez une requête qui regroupe par team les billets dont order_value est NULL. Rappelez-vous : IS NULL, pas = NULL. La vérification compare votre résultat au nôtre.

Afficher la réponse
SELECT team, COUNT(*) AS n
FROM tickets
WHERE order_value IS NULL
GROUP BY team;

Une ligne : account (compte), 188. L’équipe account compte 188 billets au total. Donc, chaque billet lié aux comptes a un order_value NULL, et aucun autre billet n’en a. Grace explique : « Les questions sur les comptes, comme la réinitialisation d’un mot de passe, n’ont pas de commande. » Ici, NULL n’est pas une valeur inconnue. Il signifie « il n’y a pas de commande ». Cette différence compte à la leçon 3.

Un système peut aussi marquer une valeur manquante par une valeur d’apparence normale, comme -1, 0, 9999 ou le texte N/A (sans objet). C’est une valeur sentinelle : une valeur qui représente « aucune valeur réelle ». Un compte des NULL ne la détecte pas. Les valeurs les plus fréquentes la révèlent souvent :

Exécutez du SQL dans votre navigateur

Essayez : les montants de commande les plus fréquents

Exécutez la requête. La première ligne est NULL (188 lignes). La deuxième ligne est -1, avec 11 lignes. Les montants réels apparaissent au plus 3 fois chacun.

Une commande ne peut pas coûter moins un dollar. Grace le confirme : le système de commandes écrit -1 lorsqu’il ne trouve pas la commande. Le profil contient donc deux types de order_value manquants : 188 NULL qui signifient « aucune commande » et 11 sentinelles qui signifient « commande inconnue ».

Il existe deux types de doublons. Un doublon exact est une ligne identique à une autre dans toutes les colonnes. Une clé répétée est une clé, ici ticket_id, qui apparaît dans plusieurs lignes, même si d’autres colonnes diffèrent. Vous avez rencontré les 14 identifiants de billets répétés au module 1. Le profil doit aussi préciser leur type.

Exécutez du SQL dans votre navigateur

Essayez : deux types de doublons

Exécutez la requête. Vous devriez voir 1 417 lignes, 1 403 identifiants distincts et 1 403 lignes distinctes.

SELECT DISTINCT * supprime seulement les doublons exacts. Il donne 1 403 lignes, soit le même nombre que les identifiants distincts. Les 14 lignes supplémentaires sont donc toutes des copies exactes. (Une page d’exportation a été envoyée deux fois.) C’est le cas simple : supprimer une copie ne fait perdre aucune information. Si les deux comptes différaient, certains billets auraient deux lignes différentes, et vous devriez décider laquelle est correcte.

Une colonne de catégories doit utiliser une liste fixe de valeurs. Pour channel, la liste est email, chat (clavardage), phone (téléphone) et web_form (formulaire Web).

Exécutez du SQL dans votre navigateur

Essayez : toutes les valeurs de canal

Exécutez la requête. Vous devriez voir 9 lignes. Trouvez les valeurs qui ne figurent pas dans la liste de quatre.

La liste de quatre, plus NULL, représente 1 377 lignes (541 + 413 + 200 + 185 + 38). Les 40 autres lignes utilisent quatre autres graphies : Email (20), chat avec une espace au début (8), EMAIL (7) et webform (5). Dans la table de résultats, l’espace dans chat est difficile à voir. GROUP BY l’affiche sur une ligne séparée, donc vous savez que la valeur est différente.

Exécutez du SQL dans votre navigateur

À vous : les segments dans la table des clients

Les segments permis sont home (particuliers), trade (professionnels) et business (entreprises). Écrivez une requête qui liste chaque graphie et son compte. Quelle graphie n’est pas permise?

Afficher la réponse
SELECT segment, COUNT(*) AS n
FROM customers
GROUP BY segment
ORDER BY n DESC;

Quatre lignes : home 166, trade 47, business 24, Trade 3. Trade est le même segment que trade, avec une majuscule.

Une colonne peut avoir un seul nom et deux unités. Pour le détecter, comparez des groupes. Si les valeurs d’un groupe sont environ 100 fois plus grandes que les autres, soupçonnez une unité différente. Mei regroupe les billets web_form par mois :

Exécutez du SQL dans votre navigateur

Essayez : les montants de commande du formulaire Web par mois

Exécutez la requête. Regardez janvier. Ensuite, remplacez 'web_form' par 'email' et exécutez-la à nouveau. Voyez-vous le même saut?

En janvier, la commande moyenne du formulaire Web est de 7 957,91 dollars. De février à juin, elle se situe entre 88,76 et 158,07 dollars. (La dernière ligne, 2036-01, correspond à un billet dont l’année est incorrecte. Vous le verrez dans la prochaine vérification.) Les commandes par courriel restent entre environ 100 et 145 dollars chaque mois. Grace connaît la raison : jusqu’au 1er février 2026, l’ancien formulaire Web envoyait le montant en cents. 4 503 cents représentent 45,03 dollars. Un modèle qui voit ces valeurs apprend que les clients du formulaire Web achètent des choses chères, ce qui est faux.

Les valeurs minimale et maximale de chaque colonne révèlent des valeurs impossibles ou très improbables.

Exécutez du SQL dans votre navigateur

Essayez : les valeurs minimale et maximale

Exécutez la requête. Vous devriez voir 4 lignes. Pour chaque ligne, demandez-vous : « Cette valeur est-elle possible? »

Colonne Minimum Maximum Ce que Mei trouve
created_at 2026-01-05 07:30:24 2036-01-24 21:27:43 Un billet est daté de 10 ans dans le futur. Il a été fermé le 25 janvier 2026, donc quelqu’un a saisi 2036 au lieu de 2026. L’extrait exclut cette ligne.
priority 1 3 Comme prévu.
order_value -1 34518 Encore la sentinelle et les cents. 25 valeurs dépassent 2 000. Parmi elles, 24 sont des billets du formulaire Web de janvier; la 25e est le billet de 2036, aussi du formulaire Web.
word_count 0 48210 Grace : 0 mot correspond à un billet contenant seulement une pièce jointe (7 lignes, valides). 48 210 mots correspondent à un billet, T-10361, où le client a collé un fichier de journaux (logs).

Certains problèmes sont visibles seulement quand vous comparez deux tables. Un billet ne peut pas exister avant le compte du client :

Exécutez du SQL dans votre navigateur

À vous : les billets antérieurs au client

Ajoutez une clause WHERE qui conserve un billet seulement si sa date précède joined_on. Prédisez d’abord le nombre de lignes.

Afficher la réponse
SELECT t.ticket_id, t.customer_id, t.created_at, c.joined_on
FROM tickets AS t
JOIN customers AS c
ON c.customer_id = t.customer_id
WHERE date(t.created_at) < c.joined_on;

3 lignes : T-11185 (créé le 25 mars 2026, inscription le 5 avril 2026), T-11224 (17 mai 2026, inscription le 24 mai 2026) et T-11375 (23 mars 2026, inscription le 10 avril 2026). Soit la date du billet, soit la date d’inscription est incorrecte, et les données ne précisent pas laquelle. Mei ne peut pas corriger ces lignes avec certitude.

Les encadrés ci-dessus utilisent le navigateur. Mei enregistre les requêtes de profil dans son projet pour les réexécuter sur une nouvelle exportation. Ouvrez un terminal dans ~/projects/ticket-data. Enregistrez ce fichier sous queries/41-profile-missing.sql :

queries/41-profile-missing.sql
-- Profile: missing values in tickets (NULL count per column).
SELECT
COUNT(*) AS ticket_rows,
COUNT(*) - COUNT(customer_id) AS no_customer_id,
COUNT(*) - COUNT(channel) AS no_channel,
COUNT(*) - COUNT(order_value) AS no_order_value,
COUNT(*) - COUNT(word_count) AS no_word_count,
COUNT(*) - COUNT(closed_at) AS no_closed_at
FROM tickets;
Terminal
python3 q.py queries/41-profile-missing.sql
Sortie
ticket_rows no_customer_id no_channel no_order_value no_word_count no_closed_at
----------- -------------- ---------- -------------- ------------- ------------
1417 12 38 188 0 12
1 row

Enregistrez les autres vérifications de la même façon, une requête par fichier : 42-profile-ranges.sql pour les valeurs minimale et maximale, et ainsi de suite. (Utilisez les prochains numéros libres dans votre dossier queries/ si vos numéros diffèrent.)

Le reste de ce module utilise pandas, une bibliothèque Python pour les tables. Une table pandas est un DataFrame : des lignes et des colonnes nommées, comme une table SQL, mais en mémoire dans votre programme Python. pandas ne fait pas partie de Python. Vous l’installez donc maintenant dans un environnement virtuel pour ce projet.

Terminal
cd ~/projects/ticket-data
python3 -m venv .venv
source .venv/bin/activate
python -m pip install pandas==3.0.6
Output (last line)
Successfully installed numpy-2.5.3 pandas-3.0.6 python-dateutil-2.9.0.post0 six-1.17.0

L’invite de commande commence maintenant par (.venv). À partir d’ici, le cours utilise python sur tous les systèmes, car l’activation fait pointer python vers l’environnement. q.py fonctionne toujours avec lui : il nécessite seulement la bibliothèque standard.

Écrivez à la main la version choisie dans requirements.txt, pour qu’un nouvel environnement obtienne la même version de pandas :

requirements.txt
pandas==3.0.6

Le profil pandas de Mei lit l’extrait, data/extract/tickets.csv. C’est le fichier utilisé par l’étape de nettoyage. Enregistrez-le sous scripts/profile.py :

scripts/profile.py
"""Profile the extracted tickets. Print counts; change nothing."""
import pandas as pd
df = pd.read_csv("data/extract/tickets.csv")
print(f"Rows: {len(df)}")
missing = df.isna().sum()
print("\nMissing values (columns with at least one):")
print(missing[missing > 0])
print(f"\nExact duplicate rows: {df.duplicated().sum()}")
print(f"Rows with a ticket_id seen before: {df.duplicated(subset='ticket_id').sum()}")
print("\nChannel values:")
print(df["channel"].value_counts(dropna=False))
print("\nRanges:")
print(df[["order_value", "word_count"]].describe().round(2))
print(f"\norder_value = -1: {(df['order_value'] == -1).sum()}")
print(f"order_value > 2000: {(df['order_value'] > 2000).sum()}")
print(f"word_count > 10000: {(df['word_count'] > 10000).sum()}")
Code Ce qu’il fait Équivalent en SQL
pd.read_csv(...) Lit le fichier CSV dans un DataFrame. la table
df.isna().sum() Compte les valeurs manquantes dans chaque colonne. COUNT(*) - COUNT(col)
df.duplicated() Marque chaque ligne qui est une copie exacte d’une ligne précédente. .sum() les compte. COUNT(*) moins SELECT DISTINCT *
df.duplicated(subset='ticket_id') Fait la même chose, mais compare seulement ticket_id. COUNT(*) - COUNT(DISTINCT ticket_id)
value_counts(dropna=False) Compte chaque valeur et inclut les valeurs manquantes. GROUP BY channel
describe() Compte, moyenne, écart-type, minimum, quartiles et maximum. MIN, MAX, AVG
Terminal
python scripts/profile.py
Sortie
Rows: 1416
Missing values (columns with at least one):
customer_id 12
channel 38
order_value 188
closed_at 12
segment 21
region 139
joined_on 21
dtype: int64
Exact duplicate rows: 14
Rows with a ticket_id seen before: 14
Channel values:
channel
email 541
chat 413
web_form 199
phone 185
NaN 38
Email 20
chat 8
EMAIL 7
webform 5
Name: count, dtype: int64
Ranges:
order_value word_count
count 1228.00 1416.00
mean 272.09 142.13
std 1262.66 1280.38
min -1.00 0.00
25% 50.28 59.00
50% 88.79 91.00
75% 164.89 134.25
max 22394.00 48210.00
order_value = -1: 11
order_value > 2000: 24
word_count > 10000: 1

Comparez-le au profil SQL. Tout compter inclut les différences :

  • 1 416 lignes, pas 1 417 : l’extrait a exclu le billet de 2036. Ce billet était un billet web_form de 34 518 cents. Donc, web_form compte ici 199 lignes, pas 200, et order_value > 2000 donne 24, pas 25.
  • pandas affiche une valeur manquante sous la forme NaN (« pas un nombre »).
  • segment, region et joined_on viennent de la jointure avec les clients dans l’extrait. Ces valeurs manquent pour 21 lignes : les 12 billets sans compte et les 9 billets dont le client est absent de la table des clients. region contient 118 valeurs manquantes supplémentaires, car 9 clients n’ont pas de région.
  • La moyenne de order_value est de 272,09 dollars, mais la médiane (50%) est de 88,79. Les cents et les valeurs -1 influencent la moyenne. Ne présentez pas cette moyenne.

Le profil est un document, pas seulement une sortie dans un terminal. Priya, la scientifique de données, le lit avant d’entraîner un modèle. Grace vérifie les significations.

  1. Créez le dossier reports dans votre projet, s’il n’existe pas.
  2. Créez le fichier reports/profile.md.
  3. Écrivez la source en haut : le fichier, son nombre de lignes et la date de l’instantané 2026-07-01 06:00.
  4. Ajoutez une section pour chacune des cinq questions. Dans chaque section, écrivez le compte et la requête ou le code qui le produit.
  5. Pour chaque valeur manquante et chaque valeur étrange, écrivez ce qu’elle signifie. Si vous ne savez pas, écrivez la question pour Grace.
  6. Ajoutez une dernière section, « Pas encore décidé ». Listez chaque problème sans correction.
  7. Exécutez python scripts/profile.py à nouveau et comparez chaque nombre de votre profil avec la sortie.
Afficher un exemple de profil
reports/profile.md
# Profile: Larkfield tickets
Source: data/extract/tickets.csv, 1,416 rows (larkfield.db has 1,417;
the extract leaves out 1 ticket created in 2036). Snapshot 2026-07-01 06:00.
Made with queries/41-profile-missing.sql, 42-profile-ranges.sql
and scripts/profile.py. Nothing changed.
## Missing values
| Column | Rows | Meaning (checked with Grace) |
|-------------|------|--------------------------------------------------|
| customer_id | 12 | guest checkout, no account |
| channel | 38 | not recorded: unknown |
| order_value | 188 | all account tickets: there is no order |
| order_value | 11 | value -1: the order system could not find it |
| closed_at | 12 | ticket still open |
| segment, region, joined_on | 21 | no customer row (12 guests, 9 deleted) |
| region | 118 more | the customer gave no region |
## Duplicates
14 rows are exact copies (export page overlap). Same count by ticket_id,
so no ticket has two different rows. 1,402 rows stay after removing them.
## Categories
channel: 40 rows use other spellings (Email 20, " chat" 8, EMAIL 7, webform 5).
segment (customers): Trade 3 next to trade 47.
## Units
order_value: web form tickets before 2026-02-01 are in cents (24 rows:
23 "web_form", 1 "webform"; January average 7,957.91). From February the
web form sends dollars.
## Ranges
word_count: 0 in 7 rows (attachment only: valid); 48,210 in T-10361 (log file).
created_at: 3 tickets before the customer's joined_on date
(T-11185, T-11224, T-11375). Which date is wrong is not known.
## Not decided yet
- What to do with the 3 tickets created before the customer joined.
- What to do with T-10361.
- How to treat the 11 unknown order values in the model.

À vous de jouer : profiler les événements de résultat

Section intitulée « À vous de jouer : profiler les événements de résultat »

Profilez la table outcomes avec les cinq mêmes questions. Utilisez la zone du navigateur ci-dessus (modifiez la requête) ou q.py. Faites d’abord une prédiction : outcomes contient-elle des lignes exactement identiques?

Afficher le profil attendu
  • Lignes : 1 874.
  • Valeurs manquantes : resolution_code vaut NULL dans 341 lignes. Seuls les événements resolved (résolus) ont un code (1 533 sur 1 533). Les événements escalated (transférés au niveau supérieur) et reopened (rouverts) n’en ont aucun. NULL signifie donc « pas encore résolu dans cet événement ». csat vaut NULL dans 959 lignes; seuls les événements resolved ont cette valeur (915 valeurs). Un client ne répond pas toujours au sondage.
  • Doublons : aucun doublon exact (1 874 lignes distinctes, 1 874 valeurs distinctes de outcome_id). Mais SELECT DISTINCT ticket_id, recorded_at, status donne 1 844 lignes : 30 événements ont été enregistrés deux fois, avec un nouveau outcome_id. Ici, la clé n’est pas l’identifiant. La recherche de doublons doit utiliser les colonnes qui décrivent l’événement.
  • Enregistrements orphelins : 4 événements appartiennent à des billets absents de tickets.
  • Catégories : status a 3 valeurs, et resolution_code en a 4, plus NULL. Toutes sont permises.
  • Plages : csat va de 1 à 5. recorded_at va jusqu’au 1 juillet 2026 à 5 h 41 min 45 s, avant l’instantané. Un événement (O-00193) précède le created_at de son billet : il appartient au billet de 2036, T-10147. La date incorrecte est donc celle du billet.

Erreur courante

Le profil indique 188 montants de commande manquants. Il y en a 199.

Symptôme : le profil compte les valeurs manquantes avec df.isna().sum() ou COUNT(*) - COUNT(order_value) et en indique 188. Le montant moyen des commandes semble un peu bas, mais rien ne plante.

Cause : les 11 valeurs -1 sont des valeurs sentinelles. Pour SQL et pandas, ce sont des nombres ordinaires. Le décompte des NULL ne les détecte pas. AVG et mean() les traitent comme un montant de moins un dollar.

Solution :

  1. Examinez les valeurs les plus petites et les plus fréquentes de chaque colonne numérique, pas seulement le décompte des NULL.
  2. Cherchez les valeurs sentinelles courantes : -1, 0, 999, 9999, et des textes comme N/A (sans objet), none (aucun) ou unknown (inconnu).
  3. Demandez au responsable des données ce que chacune signifie, et notez la réponse dans le profil.

Dans le travail en IA : un modèle entraîné sur -1 apprend que certaines commandes coûtent moins un dollar. Pire encore, si « commande inconnue » est lié au transfert au niveau supérieur, le modèle associe ce transfert à une très petite commande. Ce n’est pas vrai.

Vérifiez votre compréhension

La table tickets contient 1 417 lignes et 1 403 identifiants de billet distincts. SELECT DISTINCT * donne aussi 1 403 lignes. Qu'est-ce que cela vous apprend sur les doublons? Que signifierait un résultat de 1 410 lignes avec SELECT DISTINCT *?

Afficher la réponse

Les 14 lignes supplémentaires sont toutes des copies exactes. Vous pouvez donc les supprimer sans rien perdre. Avec 1 410 lignes distinctes, 7 des identifiants répétés auraient des lignes différentes dans au moins une colonne. Certains billets auraient alors deux versions. Vous devez trouver la bonne version avant d’en supprimer une.

Vérifiez votre compréhension

order_value vaut NULL dans 188 lignes et -1 dans 11 lignes. Ces 199 lignes signifient-elles la même chose?

Afficher la réponse

Non. Les 188 NULL correspondent exactement aux billets concernant les comptes : il n’y a aucune commande, donc aucun montant à trouver. Les 11 valeurs -1 correspondent à des commandes qui existent, mais dont le système de commandes n’a pas trouvé le montant. La valeur est inconnue. Un profil doit distinguer ces cas, car leur traitement diffère.

Vérifiez votre compréhension

Pourquoi le profil ne change-t-il rien, même quand une correction semble évidente, comme remplacer Email par email?

Afficher la réponse

Le profil est la photo « avant ». Si vous corrigez les valeurs pendant le profilage, vous ne pourrez pas compter ensuite les changements apportés par le nettoyage. De plus, le nettoyage ne sera pas regroupé dans un seul script reproductible. Certaines corrections évidentes sont aussi incorrectes : il faut parfois consulter le responsable métier pour comprendre une valeur.

Récapitulatif

  • Un profil pose cinq questions : valeurs manquantes, doublons, catégories invalides, unités incohérentes et plages suspectes. Il ne change rien.
  • Un décompte ne suffit pas. Notez ce que signifie chaque valeur manquante : ici, un order_value NULL signifie « aucune commande », et -1 signifie « inconnu ».
  • Comparez COUNT(DISTINCT key) avec SELECT DISTINCT * pour distinguer les doublons exacts des clés répétées.
  • Repérez les unités mélangées en comparant les groupes, par exemple la moyenne par mois et par canal.
  • L’extraction contient 1 416 lignes; le profil dans reports/profile.md explique chaque problème avec un décompte.

Ensuite, vous chargez l’extraction dans pandas avec le bon type pour chaque colonne, afin que pandas n’ait pas à deviner.

Leçon suivante : Transformer avec Python