🔝 Retour au Sommaire
Dans le monde réel, les données sont rarement parfaites. Elles peuvent contenir des erreurs, des valeurs manquantes, des doublons, des formats incohérents, et bien d'autres problèmes. Le nettoyage de données est une étape cruciale qui peut représenter jusqu'à 80% du temps d'un projet d'analyse de données.
Pandas offre des outils puissants pour nettoyer et transformer les données efficacement.
import pandas as pd
import numpy as np Les valeurs manquantes (NaN - Not a Number) sont très courantes dans les datasets réels. Elles peuvent survenir pour diverses raisons :
- Données non collectées
- Erreurs de saisie
- Incompatibilité lors de fusion de données
- Fichiers corrompus
# Créer un DataFrame avec des valeurs manquantes
df = pd.DataFrame({
'Nom': ['Alice', 'Bob', 'Charlie', 'David', 'Eve'],
'Âge': [25, np.nan, 35, 28, np.nan],
'Ville': ['Paris', 'Lyon', None, 'Toulouse', 'Paris'],
'Salaire': [35000, 42000, np.nan, 38000, 32000],
'Email': ['alice@mail.com', None, 'charlie@mail.com', 'david@mail.com', None]
})
print("DataFrame avec valeurs manquantes:")
print(df) Sortie :
Nom Âge Ville Salaire Email
0 Alice 25.0 Paris 35000.0 alice@mail.com
1 Bob NaN Lyon 42000.0 None
2 Charlie 35.0 None NaN charlie@mail.com
3 David 28.0 Toulouse 38000.0 david@mail.com
4 Eve NaN Paris 32000.0 None
# Vérifier si des valeurs sont manquantes (renvoie True/False)
print("Valeurs manquantes (masque booléen):")
print(df.isnull())
# Alternative : isna() fait la même chose
print("\nAvec isna():")
print(df.isna())
# Vérifier les valeurs NON manquantes
print("\nValeurs présentes:")
print(df.notnull()) # Nombre de valeurs manquantes par colonne
print("Nombre de NaN par colonne:")
print(df.isnull().sum())
# Pourcentage de valeurs manquantes
print("\nPourcentage de valeurs manquantes:")
print((df.isnull().sum() / len(df) * 100).round(2))
# Nombre total de valeurs manquantes
print(f"\nTotal de valeurs manquantes: {df.isnull().sum().sum()}")
# Lignes avec au moins une valeur manquante
lignes_avec_nan = df[df.isnull().any(axis=1)]
print(f"\nNombre de lignes avec NaN: {len(lignes_avec_nan)}") df = pd.DataFrame({
'A': [1, 2, np.nan, 4],
'B': [5, np.nan, np.nan, 8],
'C': [9, 10, 11, 12]
})
print("DataFrame original:")
print(df)
# Supprimer toutes les lignes avec au moins un NaN
df_sans_nan = df.dropna()
print("\nSans aucune ligne contenant NaN:")
print(df_sans_nan)
# Supprimer seulement si TOUTES les valeurs sont NaN
df_sans_toutes_nan = df.dropna(how='all')
print("\nSans lignes entièrement NaN:")
print(df_sans_toutes_nan)
# Supprimer les lignes avec NaN dans des colonnes spécifiques
df_sans_nan_colonne_a = df.dropna(subset=['A'])
print("\nSans NaN dans colonne A:")
print(df_sans_nan_colonne_a)
# Seuil : garder les lignes avec au moins N valeurs non-NaN
df_seuil = df.dropna(thresh=2) # Au moins 2 valeurs non-NaN
print("\nLignes avec au moins 2 valeurs non-NaN:")
print(df_seuil) df = pd.DataFrame({
'A': [1, 2, 3, 4],
'B': [np.nan, np.nan, np.nan, np.nan],
'C': [5, 6, np.nan, 8]
})
print("DataFrame original:")
print(df)
# Supprimer les colonnes avec au moins un NaN
df_sans_col_nan = df.dropna(axis=1)
print("\nSans colonnes contenant NaN:")
print(df_sans_col_nan)
# Supprimer les colonnes entièrement NaN
df_sans_col_vide = df.dropna(axis=1, how='all')
print("\nSans colonnes entièrement NaN:")
print(df_sans_col_vide) df = pd.DataFrame({
'Nom': ['Alice', 'Bob', 'Charlie'],
'Âge': [25, np.nan, 35],
'Ville': ['Paris', None, 'Lyon'],
'Score': [85, 90, np.nan]
})
print("DataFrame original:")
print(df)
# Remplir tous les NaN avec 0
df_rempli = df.fillna(0)
print("\nNaN remplacés par 0:")
print(df_rempli)
# Remplir avec une valeur spécifique par colonne
df_rempli_dict = df.fillna({
'Âge': 30,
'Ville': 'Inconnu',
'Score': 0
})
print("\nNaN remplis avec valeurs spécifiques:")
print(df_rempli_dict)
# Remplir seulement certaines colonnes
df_copie = df.copy()
df_copie['Âge'].fillna(0, inplace=True)
print("\nSeulement colonne Âge remplie:")
print(df_copie) df = pd.DataFrame({
'A': [1, 2, np.nan, 4, 5, np.nan, 7],
'B': [10, np.nan, 30, 40, np.nan, 60, 70],
'C': [100, 200, 300, np.nan, 500, 600, 700]
})
print("DataFrame original:")
print(df)
# Remplir avec la moyenne
df_mean = df.fillna(df.mean())
print("\nNaN remplis avec la moyenne:")
print(df_mean)
# Remplir avec la médiane
df_median = df.fillna(df.median())
print("\nNaN remplis avec la médiane:")
print(df_median)
# Remplir avec le mode (valeur la plus fréquente)
df_mode = df.fillna(df.mode().iloc[0])
print("\nNaN remplis avec le mode:")
print(df_mode) df = pd.DataFrame({
'Valeur': [1, np.nan, np.nan, 4, np.nan, 6]
})
print("DataFrame original:")
print(df)
# Forward fill (ffill) : propager la dernière valeur valide
df_ffill = df.ffill()
print("\nForward fill (propagation avant):")
print(df_ffill)
# Backward fill (bfill) : propager la prochaine valeur valide
df_bfill = df.bfill()
print("\nBackward fill (propagation arrière):")
print(df_bfill)
# Limiter le nombre de propagations
df_ffill_limit = df.ffill(limit=1)
print("\nForward fill avec limite de 1:")
print(df_ffill_limit) df = pd.DataFrame({
'Valeur': [1, np.nan, np.nan, 4, np.nan, 6]
})
print("DataFrame original:")
print(df)
# Interpolation linéaire
df_interpolated = df.interpolate()
print("\nInterpolation linéaire:")
print(df_interpolated)
# Interpolation polynomiale
df_poly = df.interpolate(method='polynomial', order=2)
print("\nInterpolation polynomiale:")
print(df_poly) df = pd.DataFrame({
'Âge': [25, -1, 35, 999, 28],
'Ville': ['Paris', 'N/A', 'Lyon', 'Inconnu', 'Marseille'],
'Score': [85, 0, 90, -999, 78]
})
print("DataFrame avec valeurs invalides:")
print(df)
# Remplacer une valeur spécifique par NaN
df_clean = df.replace(-1, np.nan)
print("\n-1 remplacé par NaN:")
print(df_clean)
# Remplacer plusieurs valeurs
df_clean = df.replace([-1, 999, -999], np.nan)
print("\nPlusieurs valeurs remplacées:")
print(df_clean)
# Remplacer par colonne
df_clean = df.replace({
'Ville': {'N/A': np.nan, 'Inconnu': np.nan},
'Score': {0: np.nan, -999: np.nan}
})
print("\nRemplacements par colonne:")
print(df_clean)
# Remplacer avec une regex (expressions régulières)
df_clean = df.replace(to_replace=r'^N/A$', value=np.nan, regex=True)
print("\nRemplacement avec regex:")
print(df_clean) df = pd.DataFrame({
'Nom': ['Alice', 'Bob', 'Alice', 'Charlie', 'Bob'],
'Âge': [25, 30, 25, 35, 30],
'Ville': ['Paris', 'Lyon', 'Paris', 'Marseille', 'Lyon']
})
print("DataFrame avec doublons:")
print(df)
# Identifier les lignes dupliquées (renvoie True/False)
print("\nLignes dupliquées:")
print(df.duplicated())
# Afficher les lignes dupliquées
print("\nLignes qui sont des doublons:")
print(df[df.duplicated()])
# Garder la première occurrence (marque les autres comme doublons)
print("\nDoublons (keep='first'):")
print(df.duplicated(keep='first'))
# Garder la dernière occurrence
print("\nDoublons (keep='last'):")
print(df.duplicated(keep='last'))
# Marquer TOUTES les occurrences comme doublons
print("\nDoublons (keep=False):")
print(df.duplicated(keep=False)) df = pd.DataFrame({
'Nom': ['Alice', 'Bob', 'Alice', 'Charlie', 'Bob'],
'Âge': [25, 30, 25, 35, 30],
'Ville': ['Paris', 'Lyon', 'Paris', 'Marseille', 'Lyon']
})
print("DataFrame original:")
print(df)
# Supprimer les doublons (garde la première occurrence)
df_sans_doublons = df.drop_duplicates()
print("\nSans doublons (première occurrence gardée):")
print(df_sans_doublons)
# Garder la dernière occurrence
df_last = df.drop_duplicates(keep='last')
print("\nSans doublons (dernière occurrence gardée):")
print(df_last)
# Considérer seulement certaines colonnes
df_sans_doublons_nom = df.drop_duplicates(subset=['Nom'])
print("\nSans doublons sur colonne Nom:")
print(df_sans_doublons_nom)
# Considérer plusieurs colonnes
df_sans_doublons_multiple = df.drop_duplicates(subset=['Nom', 'Âge'])
print("\nSans doublons sur Nom et Âge:")
print(df_sans_doublons_multiple) df = pd.DataFrame({
'Entier': [1, 2, 3],
'Flottant': [1.5, 2.5, 3.5],
'Texte': ['a', 'b', 'c'],
'Booleen': [True, False, True]
})
# Afficher les types de chaque colonne
print("Types de données:")
print(df.dtypes)
# Informations détaillées
print("\nInformations:")
df.info() df = pd.DataFrame({
'A': ['1', '2', '3', '4'],
'B': ['1.5', '2.5', '3.5', '4.5'],
'C': ['True', 'False', 'True', 'False']
})
print("Types originaux:")
print(df.dtypes)
print("\nDataFrame:")
print(df)
# Convertir en entier
df['A'] = df['A'].astype(int)
print("\nColonne A convertie en int:")
print(df['A'].dtype)
# Convertir en float
df['B'] = df['B'].astype(float)
print("Colonne B convertie en float:")
print(df['B'].dtype)
# Convertir en booléen
df['C'] = df['C'].map({'True': True, 'False': False})
print("Colonne C convertie en bool:")
print(df['C'].dtype)
print("\nDataFrame final:")
print(df) df = pd.DataFrame({
'Valeur': ['1', '2', '3', 'quatre', '5']
})
print("DataFrame original:")
print(df)
# Convertir en numérique (erreurs = NaN)
df['Valeur_num'] = pd.to_numeric(df['Valeur'], errors='coerce')
print("\nConversion avec erreurs -> NaN:")
print(df)
# Identifier les valeurs non convertibles
masque_valide = pd.to_numeric(df['Valeur'], errors='coerce').notna()
print("\nValeurs convertibles:")
print(df[masque_valide])
print("\nValeurs non convertibles:")
print(df[~masque_valide]) # Les catégories sont efficaces pour les colonnes avec peu de valeurs uniques
df = pd.DataFrame({
'Ville': ['Paris', 'Lyon', 'Paris', 'Marseille', 'Lyon', 'Paris'] * 1000
})
print(f"Taille en mémoire (object): {df.memory_usage(deep=True).sum()} bytes")
# Convertir en catégorie
df['Ville'] = df['Ville'].astype('category')
print(f"Taille en mémoire (category): {df.memory_usage(deep=True).sum()} bytes")
print("\nType de Ville:")
print(df['Ville'].dtype)
print("\nCatégories uniques:")
print(df['Ville'].cat.categories) df = pd.DataFrame({
'Nom': ['alice', 'BOB', 'Charlie', 'DAVID'],
'Email': ['alice@mail.com', 'bob@MAIL.com', 'charlie@mail.COM', 'david@mail.com']
})
print("DataFrame original:")
print(df)
# Convertir en majuscules
df['Nom_maj'] = df['Nom'].str.upper()
print("\nEn majuscules:")
print(df[['Nom', 'Nom_maj']])
# Convertir en minuscules
df['Email_min'] = df['Email'].str.lower()
print("\nEmail en minuscules:")
print(df[['Email', 'Email_min']])
# Capitaliser (première lettre en majuscule)
df['Nom_cap'] = df['Nom'].str.capitalize()
print("\nNom capitalisé:")
print(df[['Nom', 'Nom_cap']])
# Title case (première lettre de chaque mot)
df['Nom_title'] = df['Nom'].str.title()
print("\nTitle case:")
print(df[['Nom', 'Nom_title']]) df = pd.DataFrame({
'Texte': [' Alice ', 'Bob\n', '\tCharlie', ' David\n ']
})
print("DataFrame original (avec espaces):")
print(repr(df['Texte'].tolist()))
# Supprimer les espaces aux extrémités
df['Texte_clean'] = df['Texte'].str.strip()
print("\nAprès strip():")
print(repr(df['Texte_clean'].tolist()))
# Supprimer seulement à gauche
df['Texte_lstrip'] = df['Texte'].str.lstrip()
print("\nAprès lstrip():")
print(repr(df['Texte_lstrip'].tolist()))
# Supprimer seulement à droite
df['Texte_rstrip'] = df['Texte'].str.rstrip()
print("\nAprès rstrip():")
print(repr(df['Texte_rstrip'].tolist())) df = pd.DataFrame({
'Texte': ['Bonjour le monde', 'Python est génial', 'Pandas pour tous', 'Bonjour Python']
})
print("DataFrame original:")
print(df)
# Vérifier si contient une chaîne
df['Contient_Python'] = df['Texte'].str.contains('Python')
print("\nContient 'Python':")
print(df[['Texte', 'Contient_Python']])
# Vérifier si commence par
df['Commence_Bonjour'] = df['Texte'].str.startswith('Bonjour')
print("\nCommence par 'Bonjour':")
print(df[['Texte', 'Commence_Bonjour']])
# Vérifier si finit par
df['Finit_tous'] = df['Texte'].str.endswith('tous')
print("\nFinit par 'tous':")
print(df[['Texte', 'Finit_tous']])
# Remplacer
df['Texte_remplace'] = df['Texte'].str.replace('Python', 'Java')
print("\nPython remplacé par Java:")
print(df[['Texte', 'Texte_remplace']]) df = pd.DataFrame({
'Email': ['alice@gmail.com', 'bob@yahoo.fr', 'charlie@hotmail.com']
})
print("DataFrame original:")
print(df)
# Extraire avant le @
df['Utilisateur'] = df['Email'].str.split('@').str[0]
print("\nUtilisateur extrait:")
print(df[['Email', 'Utilisateur']])
# Extraire après le @
df['Domaine'] = df['Email'].str.split('@').str[1]
print("\nDomaine extrait:")
print(df[['Email', 'Domaine']])
# Split en plusieurs colonnes
df[['User', 'Domain']] = df['Email'].str.split('@', expand=True)
print("\nSplit en colonnes:")
print(df) df = pd.DataFrame({
'Texte': ['Bonjour', 'Python est super', 'Pandas', 'Data Science']
})
# Longueur de la chaîne
df['Longueur'] = df['Texte'].str.len()
print("Avec longueur:")
print(df)
# Compter les occurrences
df['Nombre_e'] = df['Texte'].str.count('e')
print("\nNombre de 'e':")
print(df[['Texte', 'Nombre_e']]) df = pd.DataFrame({
'Date_str': ['2024-01-01', '2024-02-15', '2024-03-30'],
'Heure_str': ['10:30:00', '14:45:30', '09:15:00']
})
print("DataFrame original:")
print(df)
print("\nTypes:")
print(df.dtypes)
# Convertir en datetime
df['Date'] = pd.to_datetime(df['Date_str'])
print("\nAprès conversion:")
print(df)
print("\nTypes:")
print(df.dtypes) # Format européen (jour/mois/année)
dates_eur = pd.Series(['15/01/2024', '20/02/2024', '10/03/2024'])
dates_conv = pd.to_datetime(dates_eur, format='%d/%m/%Y')
print("Dates européennes converties:")
print(dates_conv)
# Format américain (mois/jour/année)
dates_us = pd.Series(['01/15/2024', '02/20/2024', '03/10/2024'])
dates_conv = pd.to_datetime(dates_us, format='%m/%d/%Y')
print("\nDates américaines converties:")
print(dates_conv)
# Dates avec heure
dates_time = pd.Series(['2024-01-15 14:30:00', '2024-02-20 09:15:30'])
dates_conv = pd.to_datetime(dates_time)
print("\nDates avec heure:")
print(dates_conv) df = pd.DataFrame({
'Date': pd.to_datetime(['2024-01-15', '2024-06-20', '2024-12-25'])
})
print("DataFrame original:")
print(df)
# Extraire l'année
df['Année'] = df['Date'].dt.year
print("\nAvec année:")
print(df)
# Extraire le mois
df['Mois'] = df['Date'].dt.month
print("\nAvec mois:")
print(df)
# Nom du mois
df['Nom_mois'] = df['Date'].dt.month_name()
print("\nAvec nom du mois:")
print(df)
# Jour du mois
df['Jour'] = df['Date'].dt.day
print("\nAvec jour:")
print(df)
# Jour de la semaine (0 = lundi, 6 = dimanche)
df['Jour_semaine'] = df['Date'].dt.dayofweek
df['Nom_jour'] = df['Date'].dt.day_name()
print("\nAvec jour de la semaine:")
print(df[['Date', 'Jour_semaine', 'Nom_jour']])
# Trimestre
df['Trimestre'] = df['Date'].dt.quarter
print("\nAvec trimestre:")
print(df[['Date', 'Trimestre']]) df = pd.DataFrame({
'Date_debut': pd.to_datetime(['2024-01-01', '2024-02-01', '2024-03-01']),
'Date_fin': pd.to_datetime(['2024-01-15', '2024-02-29', '2024-03-31'])
})
print("DataFrame original:")
print(df)
# Calculer la différence (retourne un Timedelta)
df['Durée'] = df['Date_fin'] - df['Date_debut']
print("\nAvec durée:")
print(df)
# Durée en jours
df['Durée_jours'] = (df['Date_fin'] - df['Date_debut']).dt.days
print("\nDurée en jours:")
print(df)
# Ajouter des jours
df['Dans_10_jours'] = df['Date_debut'] + pd.Timedelta(days=10)
print("\nDate + 10 jours:")
print(df[['Date_debut', 'Dans_10_jours']])
# Ajouter des mois
df['Dans_1_mois'] = df['Date_debut'] + pd.DateOffset(months=1)
print("\nDate + 1 mois:")
print(df[['Date_debut', 'Dans_1_mois']]) df = pd.DataFrame({
'nom_client': ['Alice', 'Bob', 'Charlie'],
'age_client': [25, 30, 35],
'ville_client': ['Paris', 'Lyon', 'Marseille']
})
print("DataFrame original:")
print(df)
# Renommer des colonnes spécifiques
df_renomme = df.rename(columns={
'nom_client': 'Nom',
'age_client': 'Âge',
'ville_client': 'Ville'
})
print("\nColonnes renommées:")
print(df_renomme)
# Renommer avec une fonction
df_upper = df.rename(columns=str.upper)
print("\nColonnes en majuscules:")
print(df_upper)
# Renommer l'index
df_index = df.rename(index={0: 'Premier', 1: 'Deuxième', 2: 'Troisième'})
print("\nIndex renommé:")
print(df_index) df = pd.DataFrame({
'D': [1, 2, 3],
'A': [4, 5, 6],
'C': [7, 8, 9],
'B': [10, 11, 12]
})
print("DataFrame original:")
print(df)
# Réorganiser dans un ordre spécifique
df_reorg = df[['A', 'B', 'C', 'D']]
print("\nColonnes réorganisées:")
print(df_reorg)
# Mettre une colonne en premier
cols = ['D'] + [col for col in df.columns if col != 'D']
df_reorg2 = df[cols]
print("\nD en premier:")
print(df_reorg2) df = pd.DataFrame({
'Nom': ['Alice', 'Bob', 'Charlie'],
'Âge': [25, 30, 35],
'Ville': ['Paris', 'Lyon', 'Marseille']
}, index=['A', 'B', 'C'])
print("DataFrame original:")
print(df)
# Réinitialiser l'index (devient une colonne)
df_reset = df.reset_index()
print("\nIndex réinitialisé:")
print(df_reset)
# Définir une colonne comme index
df_index = df.reset_index().set_index('Nom')
print("\nNom comme index:")
print(df_index)
# Réinitialiser sans créer de colonne
df_reset_drop = df.reset_index(drop=True)
print("\nIndex réinitialisé (sans garder l'ancien):")
print(df_reset_drop) df = pd.DataFrame({
'Nom': ['Alice', 'Bob', 'Charlie'],
'Âge': [25, 30, 35],
'Salaire': [35000, 42000, 48000]
})
print("DataFrame original:")
print(df)
# Appliquer une fonction à une colonne
def categoriser_age(age):
if age < 30:
return 'Jeune'
elif age < 40:
return 'Adulte'
else:
return 'Senior'
df['Catégorie_âge'] = df['Âge'].apply(categoriser_age)
print("\nAvec catégorie d'âge:")
print(df)
# Fonction lambda
df['Salaire_mensuel'] = df['Salaire'].apply(lambda x: x / 12)
print("\nAvec salaire mensuel:")
print(df)
# apply sur plusieurs colonnes (axis=1 pour lignes)
def salaire_par_age(row):
return row['Salaire'] / row['Âge']
df['Ratio'] = df.apply(salaire_par_age, axis=1)
print("\nAvec ratio salaire/âge:")
print(df) df = pd.DataFrame({
'Ville': ['Paris', 'Lyon', 'Marseille', 'Paris', 'Lyon']
})
print("DataFrame original:")
print(df)
# Dictionnaire de mapping
code_postal = {
'Paris': 75000,
'Lyon': 69000,
'Marseille': 13000
}
df['Code_postal'] = df['Ville'].map(code_postal)
print("\nAvec code postal:")
print(df)
# map avec une fonction
df['Ville_upper'] = df['Ville'].map(str.upper)
print("\nVille en majuscules:")
print(df)
# map pour transformer les valeurs
niveau_etudes = {'Bac': 1, 'Licence': 2, 'Master': 3}
df_etudes = pd.DataFrame({'Diplôme': ['Bac', 'Master', 'Licence', 'Master']})
df_etudes['Niveau'] = df_etudes['Diplôme'].map(niveau_etudes)
print("\nNiveau d'études:")
print(df_etudes) df = pd.DataFrame({
'Note': ['A', 'B', 'C', 'A', 'D'],
'Statut': ['Actif', 'Inactif', 'Actif', 'Suspendu', 'Actif']
})
print("DataFrame original:")
print(df)
# Remplacer une valeur par une autre
df_remplace = df.replace('Actif', 'En service')
print("\nActif remplacé:")
print(df_remplace)
# Remplacer avec un dictionnaire
df_remplace = df.replace({
'A': 'Excellent',
'B': 'Bien',
'C': 'Moyen',
'D': 'Insuffisant'
})
print("\nNotes converties:")
print(df_remplace)
# Remplacer par colonne
df_remplace = df.replace({
'Note': {'A': 20, 'B': 15, 'C': 10, 'D': 5},
'Statut': {'Actif': 1, 'Inactif': 0, 'Suspendu': -1}
})
print("\nRemplacements par colonne:")
print(df_remplace) df = pd.DataFrame({
'Date': ['2024-01', '2024-01', '2024-02', '2024-02'],
'Produit': ['A', 'B', 'A', 'B'],
'Ventes': [100, 150, 120, 180]
})
print("DataFrame original:")
print(df)
# Pivoter : Date en index, Produit en colonnes
df_pivot = df.pivot(index='Date', columns='Produit', values='Ventes')
print("\nDataFrame pivoté:")
print(df_pivot) df = pd.DataFrame({
'Date': ['2024-01', '2024-01', '2024-01', '2024-02', '2024-02', '2024-02'],
'Produit': ['A', 'A', 'B', 'A', 'B', 'B'],
'Ventes': [100, 110, 150, 120, 180, 190],
'Quantité': [5, 6, 8, 7, 9, 10]
})
print("DataFrame original:")
print(df)
# Tableau croisé avec somme
pivot = pd.pivot_table(df,
values='Ventes',
index='Date',
columns='Produit',
aggfunc='sum')
print("\nTableau croisé (somme des ventes):")
print(pivot)
# Avec plusieurs fonctions d'agrégation
pivot = pd.pivot_table(df,
values='Ventes',
index='Date',
columns='Produit',
aggfunc=['sum', 'mean'])
print("\nAvec somme et moyenne:")
print(pivot)
# Avec totaux
pivot = pd.pivot_table(df,
values='Ventes',
index='Date',
columns='Produit',
aggfunc='sum',
margins=True,
margins_name='Total')
print("\nAvec lignes et colonnes de totaux:")
print(pivot) df = pd.DataFrame({
'Produit': ['A', 'B'],
'Jan': [100, 150],
'Fev': [120, 180],
'Mar': [110, 170]
})
print("DataFrame large:")
print(df)
# Transformer en format long
df_long = df.melt(id_vars=['Produit'],
var_name='Mois',
value_name='Ventes')
print("\nDataFrame long:")
print(df_long) # Créer un DataFrame avec MultiIndex
df = pd.DataFrame({
'A': [1, 2, 3],
'B': [4, 5, 6],
'C': [7, 8, 9]
}, index=['X', 'Y', 'Z'])
print("DataFrame original:")
print(df)
# stack : colonnes vers index (format long)
df_stacked = df.stack()
print("\nAprès stack (Series):")
print(df_stacked)
# unstack : index vers colonnes (format large)
df_unstacked = df_stacked.unstack()
print("\nAprès unstack:")
print(df_unstacked) df1 = pd.DataFrame({
'A': [1, 2, 3],
'B': [4, 5, 6]
})
df2 = pd.DataFrame({
'A': [7, 8, 9],
'B': [10, 11, 12]
})
print("DataFrame 1:")
print(df1)
print("\nDataFrame 2:")
print(df2)
# Concaténer verticalement (empiler)
df_concat = pd.concat([df1, df2])
print("\nConcaténation verticale:")
print(df_concat)
# Réinitialiser l'index
df_concat_reset = pd.concat([df1, df2], ignore_index=True)
print("\nAvec index réinitialisé:")
print(df_concat_reset)
# Concaténer horizontalement (côte à côte)
df3 = pd.DataFrame({
'C': [13, 14, 15],
'D': [16, 17, 18]
})
df_concat_h = pd.concat([df1, df3], axis=1)
print("\nConcaténation horizontale:")
print(df_concat_h) # DataFrame des employés
employes = pd.DataFrame({
'ID': [1, 2, 3, 4],
'Nom': ['Alice', 'Bob', 'Charlie', 'David'],
'Dept_ID': [101, 102, 101, 103]
})
# DataFrame des départements
departements = pd.DataFrame({
'Dept_ID': [101, 102, 103],
'Département': ['Ventes', 'IT', 'RH']
})
print("Employés:")
print(employes)
print("\nDépartements:")
print(departements)
# Fusion inner (intersection)
df_merge = pd.merge(employes, departements, on='Dept_ID')
print("\nFusion inner:")
print(df_merge)
# Fusion left (tous les employés)
employes2 = pd.DataFrame({
'ID': [1, 2, 3, 4, 5],
'Nom': ['Alice', 'Bob', 'Charlie', 'David', 'Eve'],
'Dept_ID': [101, 102, 101, 103, 999] # 999 n'existe pas
})
df_merge_left = pd.merge(employes2, departements, on='Dept_ID', how='left')
print("\nFusion left:")
print(df_merge_left)
# Fusion right
df_merge_right = pd.merge(employes, departements, on='Dept_ID', how='right')
print("\nFusion right:")
print(df_merge_right)
# Fusion outer (union)
df_merge_outer = pd.merge(employes2, departements, on='Dept_ID', how='outer')
print("\nFusion outer:")
print(df_merge_outer) # Dataset avec problèmes
df = pd.DataFrame({
'Date': ['2024-01-01', '2024-01-02', None, '2024-01-04', '2024-01-05'],
'Produit': ['Laptop', 'Souris', 'Clavier', 'Laptop', 'Souris'],
'Quantité': [2, None, 5, 1, 8],
'Prix': [800, 25, 60, 800, None],
'Client': [' Alice ', 'BOB', 'Charlie', 'Alice', ' bob ']
})
print("Dataset original (avec problèmes):")
print(df)
# 1. Nettoyer les noms de clients
df['Client'] = df['Client'].str.strip().str.title()
# 2. Convertir la date
df['Date'] = pd.to_datetime(df['Date'])
# 3. Gérer les valeurs manquantes
df['Quantité'].fillna(df['Quantité'].median(), inplace=True)
df['Prix'] = df['Prix'].ffill()
df.dropna(subset=['Date'], inplace=True)
# 4. Calculer le montant
df['Montant'] = df['Quantité'] * df['Prix']
# 5. Réorganiser les colonnes
df = df[['Date', 'Client', 'Produit', 'Quantité', 'Prix', 'Montant']]
print("\nDataset nettoyé:")
print(df)
# Analyse
print("\n--- Analyse ---")
print(f"Total des ventes: {df['Montant'].sum():.2f}€")
print(f"Nombre de transactions: {len(df)}")
print("\nVentes par client:")
print(df.groupby('Client')['Montant'].sum()) # Données d'enquête en format large
df = pd.DataFrame({
'ID': [1, 2, 3],
'Nom': ['Alice', 'Bob', 'Charlie'],
'Q1_Satisfaction': [5, 4, 3],
'Q2_Recommandation': [5, 5, 4],
'Q3_Prix': [3, 4, 5]
})
print("Format large:")
print(df)
# Transformer en format long
df_long = df.melt(id_vars=['ID', 'Nom'],
var_name='Question',
value_name='Score')
print("\nFormat long:")
print(df_long)
# Nettoyer les noms de questions
df_long['Question'] = df_long['Question'].str.replace('Q\\d+_', '', regex=True)
print("\nQuestions nettoyées:")
print(df_long)
# Calculer la moyenne par question
moyenne_par_question = df_long.groupby('Question')['Score'].mean()
print("\nMoyenne par question:")
print(moyenne_par_question)
# Retourner au format large
df_pivot = df_long.pivot(index=['ID', 'Nom'],
columns='Question',
values='Score')
print("\nRetour au format large:")
print(df_pivot) # Ventes janvier
ventes_jan = pd.DataFrame({
'Produit': ['A', 'B', 'C'],
'Ventes': [100, 150, 200],
'Mois': ['Jan', 'Jan', 'Jan']
})
# Ventes février
ventes_fev = pd.DataFrame({
'Produit': ['A', 'B', 'C'],
'Ventes': [120, 140, 210],
'Mois': ['Fev', 'Fev', 'Fev']
})
# Informations produits
produits = pd.DataFrame({
'Produit': ['A', 'B', 'C'],
'Nom': ['Laptop', 'Souris', 'Clavier'],
'Catégorie': ['Ordinateur', 'Accessoire', 'Accessoire'],
'Prix': [800, 25, 60]
})
print("Ventes janvier:")
print(ventes_jan)
print("\nVentes février:")
print(ventes_fev)
print("\nInfos produits:")
print(produits)
# Combiner les ventes
ventes_total = pd.concat([ventes_jan, ventes_fev], ignore_index=True)
print("\nVentes combinées:")
print(ventes_total)
# Ajouter les infos produits
ventes_complet = pd.merge(ventes_total, produits, on='Produit')
print("\nVentes avec infos produits:")
print(ventes_complet)
# Calculer le chiffre d'affaires
ventes_complet['CA'] = ventes_complet['Ventes'] * ventes_complet['Prix']
print("\nAvec chiffre d'affaires:")
print(ventes_complet)
# Analyse par catégorie et mois
analyse = ventes_complet.groupby(['Catégorie', 'Mois'])['CA'].sum().unstack()
print("\nCA par catégorie et mois:")
print(analyse) # Données de capteurs avec valeurs aberrantes
np.random.seed(42)
dates = pd.date_range('2024-01-01', periods=20, freq='h')
temperatures = np.random.normal(20, 2, 20)
# Ajouter des valeurs aberrantes
temperatures[5] = -999 # Erreur de capteur
temperatures[15] = 150 # Erreur de capteur
df = pd.DataFrame({
'DateTime': dates,
'Température': temperatures,
'Humidité': np.random.normal(60, 5, 20)
})
print("Données brutes (avec erreurs):")
print(df)
# Identifier et corriger les valeurs aberrantes
# Valeurs physiquement impossibles
df.loc[df['Température'] < -50, 'Température'] = np.nan
df.loc[df['Température'] > 60, 'Température'] = np.nan
print("\nAprès nettoyage des valeurs impossibles:")
print(df)
# Remplir avec interpolation
df['Température'].interpolate(inplace=True)
print("\nAprès interpolation:")
print(df[['DateTime', 'Température']].head(10))
# Extraire les composants de date
df['Heure'] = df['DateTime'].dt.hour
df['Date'] = df['DateTime'].dt.date
# Statistiques par heure
stats_heure = df.groupby('Heure')['Température'].agg(['mean', 'min', 'max'])
print("\nStatistiques par heure:")
print(stats_heure) # ✅ Bon
df_clean = df.copy()
df_clean['Colonne'] = df_clean['Colonne'].fillna(0)
# ❌ Risqué
# df['Colonne'] = df['Colonne'].fillna(0) # Modifie l'original# ✅ Bon : code documenté
# Étape 1 : Supprimer les valeurs manquantes
df = df.dropna(subset=['Colonne_importante'])
# Étape 2 : Normaliser les noms
df['Nom'] = df['Nom'].str.strip().str.title()
# Étape 3 : Convertir les dates
df['Date'] = pd.to_datetime(df['Date'])# ✅ Bon
print("Avant nettoyage:")
print(df.isnull().sum())
df = df.dropna()
print("\nAprès nettoyage:")
print(df.isnull().sum())
print(f"Nombre de lignes: {len(df)}") # ❌ Moins performant
df['Nouvelle_col'] = [x * 2 for x in df['Ancienne_col']]
# ✅ Meilleur (vectorisé)
df['Nouvelle_col'] = df['Ancienne_col'] * 2# ✅ Bon : gérer les erreurs potentielles
df['Numérique'] = pd.to_numeric(df['Colonne'], errors='coerce')
# Vérifier s'il y a des conversions échouées
nb_echecs = df['Numérique'].isnull().sum() - df['Colonne'].isnull().sum()
if nb_echecs > 0:
print(f"Attention: {nb_echecs} valeurs n'ont pas pu être converties")Le nettoyage et la transformation de données sont des étapes essentielles de l'analyse de données. Pandas offre des outils complets pour :
Nettoyage :
- Gérer les valeurs manquantes (détection, suppression, remplissage)
- Supprimer les doublons
- Corriger les types de données
- Nettoyer les chaînes de caractères
Transformation :
- Manipuler les dates (conversion, extraction, calculs)
- Renommer et réorganiser
- Appliquer des fonctions (apply, map, replace)
- Pivoter et restructurer (pivot, melt, stack/unstack)
- Combiner des données (concat, merge)
Points clés à retenir :
- Toujours vérifier les données avant et après transformation
- Documenter vos étapes de nettoyage
- Utiliser des méthodes vectorisées pour de meilleures performances
- Gérer les cas limites et les erreurs potentielles
- Faire des copies si nécessaire pour préserver les données originales
Dans la section suivante, nous explorerons les opérations de regroupement (GroupBy) et d'agrégation qui permettent d'analyser les données transformées de manière plus approfondie.