# ❶ 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.00
quot;.
> ```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('