# ❶ Chargement et Inspection des Données La première étape de tout projet est de charger vos données dans un format manipulable, généralement un `DataFrame` pandas, puis de les inspecter pour en comprendre la structure et la qualité initiale. ## Chargement de données pandas offre une multitude de fonctions pour lire des données depuis divers formats. Les plus courants sont CSV (Comma Separated Values) et Excel. > [!tip] Installation de pandas > Si ce n'est pas déjà fait, installez pandas via pip : `pip install pandas openpyxl` (openpyxl est nécessaire pour les fichiers Excel). ```python import pandas as pd # Chargement d'un fichier CSV df_csv = pd.read_csv('chemin/vers/mon_fichier.csv') # Chargement d'un fichier Excel # Spécifiez la feuille si nécessaire (sheet_name=0 par défaut pour la première feuille) df_excel = pd.read_excel('chemin/vers/mon_fichier.xlsx', sheet_name='MaFeuille') # Autres formats (JSON, SQL, HDF5, etc.) sont également supportés : # df_json = pd.read_json('chemin/vers/mon_fichier.json') # from sqlalchemy import create_engine # engine = create_engine('sqlite:///ma_base.db') # df_sql = pd.read_sql('SELECT * FROM ma_table', engine) ``` ## Inspection initiale des données Une fois les données chargées, il est crucial de les inspecter pour avoir un aperçu rapide de leur contenu et de leur structure. * **`df.head(n=5)`** et **`df.tail(n=5)`** : Affichent les `n` premières/dernières lignes du DataFrame. Utile pour voir les données brutes. * **`df.info()`** : Fournit un résumé concis du DataFrame, incluant le nombre d'entrées, le nombre de colonnes, les types de données de chaque colonne, le nombre de valeurs non nulles et l'utilisation de la mémoire. C'est l'un des premiers appels à faire ! * **`df.describe()`** : Génère des statistiques descriptives pour les colonnes numériques (nombre, moyenne, écart-type, min, max, quartiles). * **`df.shape`** : Retourne un tuple représentant les dimensions du DataFrame (nombre de lignes, nombre de colonnes). * **`df.columns`** : Affiche les noms des colonnes. * **`df.dtypes`** : Affiche le type de données de chaque colonne. > [!example] Inspection de base > ```python > # Supposons que 'df' est notre DataFrame chargé > print("Premières 5 lignes :") > print(df.head()) > > print("\nInformations générales :") > df.info() > > print("\nStatistiques descriptives :") > print(df.describe()) > > print(f"\nDimensions du DataFrame : {df.shape}") > print(f"Noms des colonnes : {df.columns.tolist()}") > print(f"Types de données par colonne :\n{df.dtypes}") > ``` # ❷ Gestion des Valeurs Manquantes Les valeurs manquantes sont un problème courant et peuvent sérieusement affecter l'analyse ou la performance des modèles. Elles sont généralement représentées par `NaN` (Not a Number) dans pandas. ## Détection des valeurs manquantes * **`df.isnull()`** ou **`df.isna()`** : Retourne un DataFrame de booléens de la même taille, indiquant `True` là où il y a une valeur manquante. * **`df.isnull().sum()`** : Retourne le nombre de valeurs manquantes par colonne. Très utile pour avoir un aperçu rapide. * **`df.isnull().sum().sum()`** : Retourne le nombre total de valeurs manquantes dans tout le DataFrame. * **`df.isnull().sum() / len(df) * 100`** : Calcule le pourcentage de valeurs manquantes par colonne. > [!example] Détection > ```python > print("Nombre de valeurs manquantes par colonne :") > print(df.isnull().sum()) > > print("\nPourcentage de valeurs manquantes par colonne :") > print(df.isnull().sum() / len(df) * 100) > ``` ## Stratégies de gestion des valeurs manquantes Une fois les valeurs manquantes identifiées, plusieurs stratégies s'offrent à nous : ### Suppression des lignes ou colonnes * **`df.dropna(axis=0)`** : Supprime les lignes contenant au moins une valeur manquante. * `how='any'` (par défaut) : Supprime la ligne si *n'importe quelle* colonne a un `NaN`. * `how='all'` : Supprime la ligne si *toutes* les colonnes sont `NaN`. * `subset=['col1', 'col2']` : Ne considère que les colonnes spécifiées pour la suppression. * **`df.dropna(axis=1)`** : Supprime les colonnes contenant au moins une valeur manquante. > [!warning] Attention à la suppression ! > Supprimer des lignes ou des colonnes peut entraîner une perte significative d'informations, surtout si les valeurs manquantes sont nombreuses. Utilisez cette méthode avec prudence, en particulier si le jeu de données est petit. ### Imputation (remplacement) des valeurs manquantes L'imputation consiste à remplacer les valeurs manquantes par des valeurs estimées. * **`df.fillna(value)`** : Remplace les `NaN` par une valeur spécifique. * **Par une constante** : `df['Colonne'].fillna(0)` ou `df['Colonne'].fillna('Inconnu')`. * **Par la moyenne** : `df['Colonne'].fillna(df['Colonne'].mean())`. Convient aux distributions symétriques. * **Par la médiane** : `df['Colonne'].fillna(df['Colonne'].median())`. Plus robuste aux outliers. * **Par le mode** : `df['Colonne'].fillna(df['Colonne'].mode()[0])`. Utile pour les variables catégorielles ou numériques discrètes. * **Par la valeur précédente/suivante** : `df['Colonne'].fillna(method='ffill')` (forward fill) ou `df['Colonne'].fillna(method='bfill')` (backward fill). Utile pour les séries temporelles. * **Interpolation** : `df.interpolate()` peut être utilisée pour estimer les valeurs manquantes basées sur les valeurs adjacentes, souvent dans des contextes de séries temporelles ou de données ordonnées. > [!example] Imputation > ```python > # Imputation par la moyenne pour une colonne numérique > df['Age'].fillna(df['Age'].mean(), inplace=True) > > # Imputation par le mode pour une colonne catégorielle > df['Ville'].fillna(df['Ville'].mode()[0], inplace=True) > > # Imputation par une constante pour une colonne spécifique > df['Revenu'].fillna(0, inplace=True) > > # Remplacer toutes les NaN dans le DataFrame par une valeur spécifique > df.fillna('Manquant', inplace=True) > ``` > `inplace=True` modifie le DataFrame directement. Sans cela, la fonction retourne un nouveau DataFrame modifié. # ❸ Gestion des Duplicatas Les lignes en double peuvent biaiser les analyses et sur-représenter certaines observations. Il est crucial de les identifier et de les gérer. ## Détection des duplicatas * **`df.duplicated()`** : Retourne une série de booléens indiquant si chaque ligne est un duplicata d'une ligne précédente (`True` pour les duplicatas). * **`df.duplicated().sum()`** : Compte le nombre total de lignes dupliquées. * **`df[df.duplicated()]`** : Affiche toutes les lignes dupliquées. > [!example] Détection > ```python > print(f"Nombre de lignes dupliquées : {df.duplicated().sum()}") > > if df.duplicated().sum() > 0: > print("\nExemples de lignes dupliquées :") > print(df[df.duplicated()].head()) > ``` ## Suppression des duplicatas * **`df.drop_duplicates(inplace=True)`** : Supprime les lignes dupliquées. Par défaut, la première occurrence est conservée. * `keep='first'` (par défaut) : Garde la première occurrence. * `keep='last'` : Garde la dernière occurrence. * `keep=False` : Supprime toutes les occurrences si elles sont dupliquées (ne garde aucune). * `subset=['col1', 'col2']` : Ne considère que les colonnes spécifiées pour identifier les duplicatas. > [!example] Suppression > ```python > print(f"Nombre de lignes avant suppression : {len(df)}") > df.drop_duplicates(inplace=True) > print(f"Nombre de lignes après suppression : {len(df)}") > > # Supprimer les duplicatas basés uniquement sur les colonnes 'ID_Client' et 'Date_Achat' > df.drop_duplicates(subset=['ID_Client', 'Date_Achat'], inplace=True) > ``` # ❹ Nettoyage et Transformation des Types de Données Des types de données incorrects peuvent empêcher des opérations numériques ou entraîner des erreurs. Il est essentiel de s'assurer que chaque colonne a le type approprié. ## Vérification des types de données * **`df.dtypes`** : Affiche le type de données de chaque colonne. * `object` : Généralement des chaînes de caractères (strings). * `int64` : Nombres entiers. * `float64` : Nombres à virgule flottante. * `datetime64` : Objets date et heure. * `bool` : Valeurs booléennes (True/False). ## Conversion des types de données * **`df['Colonne'].astype(type_cible)`** : Convertit une colonne vers un type spécifique. * `df['Age'].astype('int')` * `df['Prix'].astype('float')` * `df['EstActif'].astype('bool')` * **`pd.to_numeric(series, errors='coerce')`** : Convertit une série en numérique. L'argument `errors='coerce'` est crucial : il transforme les valeurs non convertibles en `NaN` au lieu de lever une erreur, ce qui permet de les gérer ensuite. * **`pd.to_datetime(series, errors='coerce')`** : Convertit une série en format datetime. > [!example] Conversion > ```python > # Convertir une colonne qui devrait être numérique mais est 'object' > df['Prix'] = pd.to_numeric(df['Prix'], errors='coerce') > > # Convertir une colonne d'entiers > df['Quantite'] = df['Quantite'].astype('int64') > > # Gérer les dates > df['Date_Commande'] = pd.to_datetime(df['Date_Commande'], errors='coerce') > ``` ## Nettoyage de chaînes de caractères Les colonnes de type `object` (strings) nécessitent souvent un nettoyage : * **Suppression d'espaces blancs** : `df['Texte'].str.strip()` * **Mise en minuscule/majuscule** : `df['Texte'].str.lower()`, `df['Texte'].str.upper()` * **Remplacement de caractères** : `df['Texte'].str.replace('€', '')` * **Extraction de motifs** : `df['Texte'].str.extract('([0-9]+)')` (utilise des expressions régulières) > [!example] Nettoyage de strings > Supposons une colonne 'Prix_Unite' avec des valeurs comme "12.50 €", " 20,00 EUR", "30.00quot;. > ```python > # Nettoyer les caractères non numériques et convertir en float > df['Prix_Unite'] = df['Prix_Unite'].str.replace('€', '').str.replace('EUR', '').str.replace(', '').str.replace(',', '.').str.strip() > df['Prix_Unite'] = pd.to_numeric(df['Prix_Unite'], errors='coerce') > ``` # ❺ Gestion des Outliers (Valeurs Aberrantes) Les outliers sont des points de données qui s'écartent significativement des autres observations. Ils peuvent être le résultat d'erreurs de mesure, d'erreurs de saisie, ou représenter des événements rares mais légitimes. Ils peuvent fausser les statistiques descriptives et impacter la performance des modèles. > [!warning] Définition d'un outlier > Il n'y a pas de définition unique d'un outlier. C'est souvent contextuel et dépend du domaine d'application. Une valeur aberrante n'est pas nécessairement une erreur ; elle peut être une information cruciale. ## Détection des outliers (méthodes courantes) * **Visualisation** : * **Box plots** (diagrammes en boîte) : Excellent pour visualiser la distribution d'une variable numérique et identifier les points au-delà des "moustaches". * **Scatter plots** (nuages de points) : Utile pour détecter des outliers en relation avec d'autres variables. * **Histogrammes** : Peuvent révéler des valeurs extrêmes. * **Méthodes statistiques** : * **Règle de l'écart interquartile (IQR)** : * Calcul du premier quartile ($Q_1$) et du troisième quartile ($Q_3$). * Calcul de l'IQR : $IQR = Q_3 - Q_1$. * Les outliers sont souvent définis comme les points inférieurs à $Q_1 - 1.5 \times IQR$ ou supérieurs à $Q_3 + 1.5 \times IQR$. * **Z-score** : Pour une distribution normale, les valeurs avec un Z-score élevé (par exemple, $|Z| > 3$) sont considérées comme des outliers. * $Z = \frac{X - \mu}{\sigma}$ où $\mu$ est la moyenne et $\sigma$ est l'écart-type. > [!theorem] Règle de l'IQR pour les outliers > Un point de donnée $x$ est considéré comme un outlier si : > $x < Q_1 - 1.5 \times IQR$ > ou > $x > Q_3 + 1.5 \times IQR$ > où $Q_1$ est le premier quartile (25ème percentile), $Q_3$ est le troisième quartile (75ème percentile), et $IQR = Q_3 - Q_1$. > [!theorem] Z-score pour les outliers > Un point de donnée $x$ est considéré comme un outlier si son Z-score est en dehors d'un certain seuil (souvent $\pm 2$ ou $\pm 3$). > Le Z-score est calculé comme suit : > $ Z = \frac{x - \mu}{\sigma} $ > où $\mu$ est la moyenne de la distribution et $\sigma$ est l'écart-type de la distribution. ## Stratégies de gestion des outliers * **Suppression** : Supprimer les lignes contenant des outliers. (Mêmes précautions que pour les valeurs manquantes). * **Transformation** : Appliquer des transformations (logarithmique, racine carrée) pour réduire l'impact des valeurs extrêmes et rendre la distribution plus symétrique. * Ex: `df['Colonne_Log'] = np.log(df['Colonne'])` * **Winsorisation/Capping** : Remplacer les outliers par les valeurs minimales ou maximales acceptables (par exemple, remplacer les valeurs au-dessus de $Q_3 + 1.5 \times IQR$ par cette limite). * **Imputation** : Remplacer les outliers par la moyenne, la médiane, etc. (moins courant). > [!note] Pas de solution unique > La gestion des outliers est un art autant qu'une science. La meilleure approche dépend de la nature des données et des objectifs de l'analyse. # ❻ Encodage des Variables Catégorielles De nombreux algorithmes de Machine Learning ne peuvent traiter que des entrées numériques. Les variables catégorielles (par exemple, "Ville", "Couleur", "Statut") doivent donc être converties en représentations numériques. ## Identification des variables catégorielles * Utilisez `df.select_dtypes(include='object')` pour identifier les colonnes de type chaîne de caractères. * Utilisez `df['Colonne'].nunique()` pour voir le nombre de catégories uniques. ## Techniques d'encodage ### One-Hot Encoding (Encodage à chaud) Crée de nouvelles colonnes binaires (0 ou 1) pour chaque catégorie unique. Une colonne est créée pour chaque valeur distincte de la variable catégorielle. Si une observation appartient à une catégorie, la colonne correspondante aura 1, sinon 0. * **Avantages** : Convient aux catégories nominales (sans ordre inhérent). Évite d'imposer un ordre artificiel. * **Inconvénients** : Peut créer un grand nombre de colonnes (problème de "malédiction de la dimensionnalité") si la variable a beaucoup de catégories uniques. ```python # Utilisation de pd.get_dummies() df_encoded = pd.get_dummies(df, columns=['Ville', 'Couleur'], prefix=['Ville', 'Couleur']) # 'drop_first=True' pour éviter la multicolinéarité (si n catégories, n-1 colonnes) df_encoded = pd.get_dummies(df, columns=['Ville', 'Couleur'], drop_first=True) ``` > [!example] One-Hot Encoding > Si vous avez une colonne `Couleur` avec 'Rouge', 'Bleu', 'Vert' : > > | Couleur | > | :------ | > | Rouge | > | Bleu | > | Vert | > | Rouge | > > Après `pd.get_dummies(df, columns=['Couleur'])` : > > | Couleur_Bleu | Couleur_Rouge | Couleur_Vert | > | :----------- | :------------ | :----------- | > | 0 | 1 | 0 | > | 1 | 0 | 0 | > | 0 | 0 | 1 | > | 0 | 1 | 0 | ### Label Encoding (Encodage par étiquettes) Attribue un entier unique à chaque catégorie. * **Avantages** : Simple, ne crée pas de nouvelles colonnes. * **Inconvénients** : Implique un ordre ou une relation d'échelle entre les catégories, ce qui peut être trompeur pour les algorithmes (par exemple, "Rouge" = 1, "Bleu" = 2, "Vert" = 3 suggère que Vert > Bleu > Rouge, ce qui n'est généralement pas le cas). À n'utiliser que pour les variables ordinales (avec un ordre). > [!tip] Label Encoding avec scikit-learn > Pour le Label Encoding, on utilise généralement la classe `LabelEncoder` de `sklearn.preprocessing`. > ```python > from sklearn.preprocessing import LabelEncoder > > le = LabelEncoder() > df['Taille_Encoded'] = le.fit_transform(df['Taille']) # Ex: 'S', 'M', 'L' -> 0, 1, 2 > ``` > Nous aborderons `scikit-learn` plus en détail dans les chapitres suivants. # ❼ Normalisation et Standardisation (Mise à l'échelle) Certains algorithmes de Machine Learning sont sensibles à l'échelle des variables d'entrée. Si une variable a une plage de valeurs beaucoup plus grande qu'une autre, elle pourrait dominer le processus d'apprentissage. La mise à l'échelle des données est cruciale pour ces algorithmes (par exemple, K-Means, SVM, PCA, réseaux de neurones). ## Normalisation (Min-Max Scaling) Redimensionne les valeurs d'une variable pour qu'elles se situent dans une plage spécifique, généralement $[0, 1]$. > [!theorem] Formule de Normalisation (Min-Max Scaling) > Pour une valeur $X$ dans une colonne, la valeur normalisée $X_{norm}$ est calculée comme suit : > $ X_{norm} = \frac{X - X_{min}}{X_{max} - X_{min}} $ > où $X_{min}$ est la valeur minimale de la colonne et $X_{max}$ est la valeur maximale de la colonne. * **Avantages** : Les données sont bornées dans une plage fixe. * **Inconvénients** : Très sensible aux outliers, car ils affectent $X_{min}$ et $X_{max}$. ## Standardisation (Z-score Scaling) Redimensionne les valeurs pour qu'elles aient une moyenne de 0 et un écart-type de 1. > [!theorem] Formule de Standardisation (Z-score Scaling) > Pour une valeur $X$ dans une colonne, la valeur standardisée $X_{std}$ est calculée comme suit : > $ X_{std} = \frac{X - \mu}{\sigma} $ > où $\mu$ est la moyenne de la colonne et $\sigma$ est l'écart-type de la colonne. * **Avantages** : Moins sensible aux outliers que la normalisation. Les données n'ont pas de bornes fixes. * **Inconvénients** : Ne garantit pas une plage de valeurs spécifique. > [!tip] Quand utiliser quoi ? > * **Normalisation** : Préférable lorsque vous savez que la distribution n'est pas gaussienne et que vous voulez que les valeurs soient dans une plage spécifique (ex: pour des algorithmes basés sur des distances comme KNN ou des réseaux de neurones qui attendent des entrées entre 0 et 1). > * **Standardisation** : Préférable lorsque la distribution est approximativement gaussienne, ou lorsque les algorithmes assument une distribution normale (ex: régression linéaire, logistique, SVM). C'est souvent le choix par défaut. > [!note] Implémentation avec scikit-learn > Ces transformations sont généralement effectuées avec les classes `MinMaxScaler` et `StandardScaler` de `sklearn.preprocessing`. > ```python > from sklearn.preprocessing import MinMaxScaler, StandardScaler > > # Normalisation > scaler_minmax = MinMaxScaler() > df['Colonne_Normalisee'] = scaler_minmax.fit_transform(df[['Colonne']]) > > # Standardisation > scaler_std = StandardScaler() > df['Colonne_Standardisee'] = scaler_std.fit_transform(df[['Colonne']]) > ``` > Nous approfondirons ces outils dans les modules dédiés au Machine Learning avec Python. # ➡️ C'est la fin Dans ce chapitre, nous avons couvert les bases essentielles : 1. **Chargement et inspection** pour comprendre vos données. 2. **Gestion des valeurs manquantes** (suppression ou imputation) pour assurer la complétude. 3. **Gestion des duplicatas** pour éviter les biais. 4. **Nettoyage et transformation des types** pour la cohérence et la compatibilité. 5. **Détection et gestion des outliers** pour la robustesse. 6. **Encodage des variables catégorielles** pour les rendre utilisables par les modèles. 7. **Mise à l'échelle des variables numériques** pour optimiser la performance des algorithmes. --- - Cours précèdent: `cours-de-départ` - Prochain cours: [[Cours 2 - Pré-traiter avec Python]] - Page d'accueil de la compétence: [[Pré-traiter avec Python]] # 🗓️ Historique - Dernière MAJ: `13-Octobre-2025` - Rédigé par: [[Hamilton DE ARAUJO]]