L’analyse exploratoire des données (EDA, exploratory data analysis) consiste à comprendre un jeu de données avant de le modéliser ou d’en tirer des conclusions : sa structure, sa qualité, ses distributions et ses relations. C’est l’étape où l’on découvre les pièges… et les premières pistes.
Commencer par les questions et le grain
Avant de coder, deux questions :
- Que veut-on savoir ? « Quelles régions et catégories portent le chiffre d’affaires ? Y a-t-il une saisonnalité ? »
- Que représente une ligne ? Une commande, une ligne de commande, un client, un jour ? Ce grain conditionne tous les calculs : sommer des montants de lignes de commande n’a pas le même sens que compter des commandes.
La revue de base
import pandas as pd
ventes = pd.DataFrame({
"commande_id": [101, 102, 103, 104],
"date": ["2026-01-03", "2026-01-04", "2026-01-04", "2026-01-10"],
"region": ["Nord", "Sud", "Nord", "Est"],
"quantite": [2, 1, 3, 1],
"montant": ["39,90", "12,50", "59,85", "24,00"], # virgule décimale : lu comme texte
})
print(ventes.shape) # (4, 5) : 4 lignes, 5 colonnes
print(ventes.head()) # aperçu des premières lignes
print(ventes.dtypes) # type de chaque colonne
ventes.info() # types, valeurs non nulles, mémoire
print(ventes.describe()) # statistiques des colonnes numériques
print(ventes.nunique()) # nombre de valeurs distinctes par colonne
Lecture attentive des résultats :
montantest de type str : la virgule décimale l’a empêché d’être lu comme un nombre. Depuis pandas 3, le texte a par défaut le typestr(auparavantobject).dateest aussi du texte : impossible de trier ou grouper par mois correctement.commande_idest numérique, mais c’est un identifiant : sa moyenne dansdescribe()n’a aucun sens. Vérifiernunique()== nombre de lignes confirme qu’il identifie bien chaque ligne.
Corriger les types
ventes["montant"] = pd.to_numeric(ventes["montant"].str.replace(",", ".", regex=False))
ventes["date"] = pd.to_datetime(ventes["date"], errors="coerce")
print(ventes.dtypes) # montant float64, date datetime64
errors="coerce" transforme les valeurs impossibles à convertir en valeurs manquantes (NaT pour les dates) au lieu de lever une erreur. Contrôle toujours combien de valeurs ont été perdues :
print(ventes["date"].isna().sum())
Sélectionner par type
numeriques = ventes.select_dtypes(include="number").columns.tolist()
autres = ventes.select_dtypes(exclude="number").columns.tolist()
print(ventes.describe(include="all")) # résumé de toutes les colonnes
Noter ses observations
Garde une liste au fil de l’eau : « montant importé en texte », « 3 régions seulement », « période de janvier à mars ». Ce journal deviendra la base de ta synthèse finale.
À retenir
- Questions métier et grain d’abord.
- shape, dtypes, info, describe, nunique : le profil de départ.
- Corrige les types, puis vérifie les valeurs perdues à la conversion.
Exercices
Les solutions et les tests restent sur le serveur. Dans l'espace étudiant, ton code est exécuté et corrigé, et le tuteur donne des indices avant la solution.
Fonction de profil
Écris
profil(df)qui renvoie un dictionnaire avec les clésn_lignes,n_colonnes,numeriques(liste des colonnes numériques) etcle_unique(True si la colonnecommande_ida autant de valeurs distinctes que de lignes).import pandas as pd ventes = pd.DataFrame({ 'commande_id': [101, 102, 103, 104, 105, 106, 107, 108], 'date': ['2026-01-03', '2026-01-04', '2026-01-04', '2026-01-10', '2026-02-02', '2026-02-03', '2026-02-15', '2026-03-01'], 'region': ['Nord', 'Sud', 'Nord', 'Est', 'Sud', 'Nord', 'Est', 'Sud'], 'categorie': ['jeux', 'livres', 'jeux', 'deco', 'livres', 'deco', 'jeux', 'livres'], 'quantite': [2, 1, 3, 1, 2, 4, 1, 2], 'montant': ['39,90', '12,50', '59,85', '24,00', '25,00', '96,00', '19,95', '25,00'], }) def profil(df): passCorriger les types
Convertis
montanten nombre (remplace la virgule par un point) etdateen datetime avecerrors='coerce'. Stocke ensuite dansnb_dates_invalidesle nombre de dates non converties et dansca_totalla somme des montants.import pandas as pd ventes = pd.DataFrame({ 'date': ['2026-01-03', '2026-01-04', '2026-02-30', '2026-03-01'], 'montant': ['39,90', '12,50', '59,85', '24,00'], }) # conversions puis nb_dates_invalides et ca_totalLe grain des données
Un fichier contient une ligne par produit commandé : la commande 12 apparaît 3 fois (3 produits). Pour compter le nombre de commandes, que faut-il utiliser ?
- len(df)
- df['commande_id'].nunique()
- df['commande_id'].sum()
- df.shape[1]
Quiz de fin de leçon
Depuis pandas 3, quel est le type par défaut d’une colonne de texte ?
- object
- str
- category
Que fait pd.to_datetime(s, errors=‘coerce’) face à une date invalide ?
- Il lève une erreur
- Il la remplace par NaT
- Il la supprime de la série
Par défaut, describe() résume :
- Toutes les colonnes
- Les colonnes numériques
- Les colonnes de texte
La suite du cours
- Valeurs manquantes et doublons18 min
- Analyse univariée : distributions et catégories18 min
- Analyse bivariée : croiser les variables20 min
- Anomalies, évolution temporelle et synthèse de l'EDA20 min