You are currently viewing Analyser les données avec Python
Python Data Analyst
  • Dernière modification de la publication :8 février 2026
  • Temps de lecture :39 mins read
  • Post category:Python

Analyser les données avec Python

Qu’est-ce qu’un Data Analyst ?

Le Data Analyst est un « traducteur de données ». Son rôle est de transformer des millions de lignes brutes (logs, ventes, sondages) en informations exploitables.
Concrètement, il collecte les données, les nettoie, les explore statistiquement pour détecter des signaux (tendances, anomalies), et enfin, il présente ses découvertes pour aider l’entreprise à prendre des décisions stratégiques factuelles, et non basées sur l’intuition.

Pourquoi Python est-il le standard de l’industrie ?

Python a écrasé la concurrence (Excel, R, SAS) pour devenir le langage n°1 de la Data. Voici pourquoi :

  • Une courbe d’apprentissage douce : Sa syntaxe ressemble à de l’anglais. On passe plus de temps à réfléchir au problème qu’à se battre avec le code.
  • L’Armée des Bibliothèques : Vous ne partez jamais de zéro.
    • Besoin de manipuler des tableaux ? ➝ Pandas.
    • Besoin de maths complexes ? ➝ NumPy.
    • Besoin de graphiques ? ➝ Seaborn.
    • Besoin d’IA ? ➝ Scikit-Learn.
  • La « Glue » Universelle : Python s’intègre partout. Il peut lire un fichier Excel, interroger une base SQL, scraper un site web et envoyer le rapport par email, le tout dans le même script.
  • Une Communauté Mondiale : Si vous avez un bug, quelqu’un d’autre l’a déjà eu et la solution est déjà en ligne (StackOverflow, GitHub). C’est un atout majeur pour ne jamais rester bloqué.

Installation et Configuration

Option 1 : installer Anaconda

# 1) Télécharger et installer Anaconda (inclut Python + de nombreux outils)
# https://www.anaconda.com/products/distribution

# 2) Vérifier que Python est bien installé
python --version
# ou (selon votre système)
python3 --version

Option 2 : installer Python “classique”, puis utiliser pip

# 1) Installer Python depuis le site officiel (pip sera inclus)
# https://www.python.org/downloads/

# 2) Vérifier l'installation
python --version
# ou
python3 --version

# 3) Vérifier pip
pip --version
# ou
pip3 --version

pip sert à installer des packages Python (des bibliothèques comme requestsnumpy, etc.), mais il ne permet pas d’installer Python lui-même. Anaconda est souvent recommandé aux débutants (ou en data science) car il installe Python et facilite la gestion d’environnements et de dépendances, tandis que l’installation “classique” via python.org est plus légère et convient très bien pour du développement général.

Bibliothèques Essentielles

# Installation des bibliothèques (dans votre environnement virtuel si possible)
python -m pip install --upgrade pandas numpy matplotlib seaborn scikit-learn

# Pour travailler dans des notebooks :
python -m pip install jupyter notebook

Cette commande installe les outils de base pour l’analyse de données et le machine learning : numpy/pandas (calcul + données), matplotlib/seaborn (graphiques), scikit-learn (ML), ainsi que jupyter/notebook pour exécuter du code dans des carnets interactifs. Si vous avez déjà un projet, lancez ces commandes depuis le dossier du projet avec l’environnement virtuel activé pour garder une installation propre.

Environnement de Développement virtuel

# 1. Créer un environnement isolé (ici nommé "data_analytics_env")
python -m venv data_analytics_env

# 2. Activer l'environnement

# Sur Windows (PowerShell ou CMD) :
.\data_analytics_env\Scripts\activate

# Sur Mac / Linux :
source data_analytics_env/bin/activate

# 3. Pour désactiver l'environnement (quand vous avez fini) :
deactivate

Créer un environnement virtuel est une « bonne pratique » indispensable en Python. Cela permet d’isoler votre projet dans une bulle étanche : les bibliothèques que vous installerez ici n’entreront pas en conflit avec celles d’autres projets ou avec le système global. Une fois activé, votre terminal affichera généralement le nom (data_analytics_env) au début de la ligne de commande pour confirmer que vous êtes bien dans l’environnement.

Les bases de Pyhton pour l’Analyse de Données

# Nombres
# --- 1. Types Numériques ---
# Essentiels pour les calculs et les statistiques
nb_utilisateurs = 42          # int (entier)
prix_moyen = 19.99            # float (nombre décimal)

# --- 2. Chaînes de caractères (Textes) ---
# Utiles pour le nettoyage de données et les catégories
job_title = "Data Analyst"
# f-string : méthode moderne pour insérer des variables dans du texte
message = f"Bienvenue au poste de {job_title}"

# --- 3. Structures de collection ---

# Listes : Séquences modifiables (mutables)
# Idéales pour stocker des séries de données (ex: une colonne de tableau)
valeurs_mensuelles = [120, 130, 150, 170, 90]
liste_mixte = [1, "Catégorie A", 3.5, True]

# Dictionnaires : Paires Clé-Valeur
# Structure proche du format JSON, très utilisée pour structurer une entité
profil_client = {
    "id": 1024,
    "nom": "Dupont",
    "est_actif": True
}

# Tuples : Séquences immuables (non modifiables)
# Utilisés pour protéger des données fixes (ex: dimensions, géolocalisation)
coordonnees_gps = (48.8566, 2.3522)

En analyse de données, il est crucial de distinguer ces structures :

  • Les Listes ([]) sont flexibles et deviendront souvent les colonnes de vos tableaux (DataFrames).
  • Les Dictionnaires ({}) permettent d’associer des étiquettes à des valeurs, exactement comme on le fait en NoSQL ou avec des fichiers JSON.
  • Les Tuples (()) sont une sécurité : ils garantissent que certaines données de référence (comme des coordonnées géographiques) ne seront pas modifiées par erreur par votre script.

Structures de Contrôle

import pandas as pd
import numpy as np

# --- 1. Conditions (Logique classique) ---
age = 25

if age >= 18:
    statut = "Majeur"
elif age >= 13:
    statut = "Adolescent"
else:
    statut = "Mineur"
print(f"Statut : {statut}")


# --- 2. Boucles vs Compréhensions (Python Standard) ---
# Au lieu d'une boucle 'for' verbeuse, on utilise souvent les list comprehensions
# pour créer des listes proprement et rapidement.

villes = ["Paris", "Lyon", "Marseille"]

# Version compacte (List Comprehension)
villes_maj = [ville.upper() for ville in villes]
print(f"Villes formatées : {villes_maj}")

# Déballage d'arguments (Astuce d'affichage)
# L'étoile (*) permet d'afficher le contenu sans les crochets []
print(*villes, sep=" | ")


# --- 3. L'Approche Data Analyst (Vectorisation) ---
# En Data Science, on ÉVITE les boucles 'for' sur les données.
# On utilise Pandas et Numpy qui traitent toute la colonne d'un coup (Vectorisation).

df = pd.DataFrame({"Villes": ["Paris", "Lyon", "Marseille"], "Note": [10, 15, 12]})

# MAUVAISE PRATIQUE (Lente) : Boucle for ou .apply() simple
# df["Villes"].apply(print) 

# BONNE PRATIQUE (Rapide) : Opérations vectorielles
# Pandas applique la transformation à toute la colonne instantanément
df["Villes_Maj"] = df["Villes"].str.upper()
df["Note_Sur_20"] = df["Note"] + 5  # Addition appliquée à toutes les lignes sans boucle

print("\nDataFrame transformé :")
print(df)

# Génération de séquences avec Numpy (Plus rapide que range() pour les gros volumes)
sequence = np.arange(5)


Ce script met en lumière une transition fondamentale pour un Data Analyst :

La Vectorisation (la partie Pandas/Numpy) est cruciale. Au lieu de traiter les données ligne par ligne avec une boucle (ce qui est très lent sur des millions de lignes), on applique une opération sur toute la colonne (le « vecteur ») d’un coup. C’est le secret de la performance en Python.

Les Conditions restent classiques (if/else).

Les Boucles traditionnelles sont souvent remplacées par des list comprehensions ([x for x in liste]) pour manipuler des petites listes Python, car c’est plus lisible et plus rapide.

Fonctions

# --- Définition de la fonction avec typage ---
def calculer_moyenne(nombres: list[float]) -> float:
    """
    Calcule la moyenne arithmétique d'une liste de nombres.
    Retourne 0.0 si la liste est vide.
    """
    # Vérification "Pythonique" : une liste vide est considérée comme False
    if not nombres:
        return 0.0
    
    return sum(nombres) / len(nombres)

# --- Utilisation ---
liste_notes = [10, 20, 30, 40]
resultat = calculer_moyenne(liste_notes)

print(f"La moyenne est de : {resultat}")


# --- Note pour l'Analyse de Données ---
# En situation réelle (Data Science), on préférera souvent utiliser 
# des bibliothèques optimisées comme Numpy plutôt que de coder la fonction soi-même :
import numpy as np
print(f"Moyenne via Numpy : {np.mean(liste_notes)}")

Les fonctions servent à encapsuler une logique pour ne pas la répéter.
L’ajout de nombres: list[float] et -> float ne change pas l’exécution, mais aide les développeurs (et les outils d’autocorrection) à comprendre que la fonction attend une liste de nombres et renverra un nombre décimal. Enfin, le test if not nombres est la méthode la plus élégante en Python pour vérifier si une liste est vide avant de faire un calcul.

Pandas – Manipulation de Données

Importation et Configuration

import pandas as pd
import numpy as np

# --- Configuration de l'affichage dans la console ---

# 1. Afficher toutes les colonnes (évite les "..." au milieu du tableau)
pd.set_option('display.max_columns', None)

# 2. (Recommandé) Élargir la zone d'affichage pour éviter les retours à la ligne
pd.set_option('display.width', 1000)

# 3. (Optionnel) Limiter les décimales à 2 chiffres pour la lisibilité
pd.set_option('display.float_format', '{:.2f}'.format)

print("Bibliothèques chargées et affichage configuré.")

L’importation avec les alias pd et np est une convention universelle : tous les développeurs Python s’attendent à ces abréviations.
Concernant la configuration : par défaut, Pandas masque les colonnes centrales des grands tableaux pour économiser de la place à l’écran. L’option display.max_columns = None force l’affichage de toutes les données horizontales, ce qui est crucial lors de la phase d’exploration pour ne rater aucune variable.

Création de DataFrame (Tableaux de données)

# --- 1. Création manuelle (Dictionnaire) ---
# Méthode intuitive : Clé = Nom de colonne, Valeur = Liste de données
data_dict = {
    'Nom': ['Alice', 'Bob', 'Charlie'],
    'Age': [25, 30, 35],
    'Salaire': [50000, 60000, 70000]
}
df = pd.DataFrame(data_dict)
print("DataFrame via Dictionnaire :\n", df)


# --- 2. Création manuelle (Liste de listes) ---
# Utile quand on récupère des données ligne par ligne (ex: scraping, logs)
raw_data = [
    ['Alice', 25, 50000],
    ['Bob', 30, 60000],
    ['Charlie', 35, 70000]
]
df2 = pd.DataFrame(raw_data, columns=['Nom', 'Age', 'Salaire'])


# --- 3. Cas Réel : Import de fichier ---
# En pratique, vous chargerez surtout des données existantes
# df_csv = pd.read_csv('donnees.csv')
# df_excel = pd.read_excel('rapport.xlsx')

Un DataFrame est l’objet central de Pandas : imaginez-le comme une feuille Excel programmable.
La méthode par dictionnaire est souvent préférée pour créer de petits tableaux de test car elle est très lisible (on voit immédiatement quelle donnée va dans quelle colonne). La méthode par liste est plus structurelle et ressemble à la manière dont les données sont stockées dans une base de données (ligne par ligne).

Lecture de Fichiers (Importation de Données)

# --- 1. Lecture de fichier CSV (Comma Separated Values) ---
# Le format le plus courant.
# On spécifie souvent le séparateur (',' ou ';') et l'encodage pour éviter les erreurs.
try:
    df_csv = pd.read_csv('donnees.csv', sep=',', encoding='utf-8')
    print("CSV chargé avec succès.")
except FileNotFoundError:
    print("Erreur : Le fichier 'donnees.csv' est introuvable.")

# --- 2. Lecture de fichier Excel (.xlsx) ---
# Nécessite souvent l'installation de 'openpyxl' (pip install openpyxl).
# L'option 'sheet_name' permet de cibler un onglet précis (par défaut le premier).
df_excel = pd.read_excel('donnees.xlsx', sheet_name='Feuille1')

# --- 3. Lecture de fichier JSON ---
# Format standard du web. 'orient' aide Pandas à comprendre la structure du JSON.
df_json = pd.read_json('donnees.json')

# --- Astuce Pro : Aperçu rapide ---
# Affichez toujours les 5 premières lignes pour vérifier que l'import s'est bien passé.
print(df_csv.head())

Lire un fichier semble simple, mais c’est souvent la première source d’erreurs (fichier manquant, mauvais format, caractères bizarres…).

  • Pour le CSV : Le piège classique est le séparateur. Si votre fichier utilise des points-virgules ; (fréquent en France) au lieu de virgules ,, Pandas ne séparera pas les colonnes correctement. L’argument sep=';' corrige cela.​
  • Pour Excel : Contrairement au CSV qui est du texte brut, le .xlsx est un format binaire complexe. Pandas utilise des « moteurs » comme openpyxl en arrière-plan pour le lire.
  • Pour JSON : Très flexible, ce format peut parfois avoir des structures imbriquées qui demandent des ajustements spécifiques, mais read_json gère très bien les formats standards.

Exploration de la DataFrame (aperçu & diagnostics)

# --- Aperçu rapide ---
print(df.head(5))          # 5 premières lignes
print(df.tail(5))          # 5 dernières lignes

# --- Structure & types ---
df.info()                  # Affiche les colonnes, types, valeurs non nulles (retourne None)

# --- Statistiques descriptives ---
print(df.describe())       # Numériques par défaut
print(df.describe(include="all"))  # Optionnel : inclut aussi les colonnes texte/catégorielles

# --- Dimensions & métadonnées ---
print(df.shape)            # (nb_lignes, nb_colonnes)
print(df.columns.tolist()) # Noms de colonnes en liste

Sélection de données (colonnes, lignes, cellules)

# --- Sélection de colonnes ---
noms = df["Nom"]                    # Série (1 colonne)
sous_table = df[["Nom", "Age"]]     # DataFrame (plusieurs colonnes)

# --- Sélection de lignes ---
premiere_ligne = df.iloc[0]         # Par position (0 = 1ère ligne)
plus_de_25 = df.loc[df["Age"] > 25] # Filtre conditionnel (masque booléen)

# --- Sélection mixte (ligne/colonne) ---
cellule = df.loc[0, "Nom"]          # 1 valeur (index de ligne, nom de colonne)

# (Bon réflexe) Si vous comptez modifier un sous-ensemble filtré :
plus_de_25 = df.loc[df["Age"] > 25].copy()

L’exploration sert à valider rapidement que vos données sont bien chargées (forme, colonnes, types, valeurs manquantes) avant toute analyse. Pour sélectionner des données, retenez : iloc fonctionne par positions (comme “ligne 0, colonne 2”), tandis que loc fonctionne par labels (index/nom de colonne) et s’utilise très bien avec des filtres comme df["Age"] > 25.

Pandas fournit aussi des fonctions dédiées pour importer des fichiers, par exemple read_csv() et read_excel() pour démarrer une analyse à partir de CSV/Excel.

Opérations sur les Données (Filtrer, Trier, Agréger)

# --- 1. Filtrage (Sélection conditionnelle) ---
# On crée un masque logique pour ne garder que certaines lignes.
# .copy() assure que vous travaillez sur un nouvel objet indépendant.
jeunes = df[df['Age'] < 30].copy()
hauts_salaires = df[df['Salaire'] > 55000].copy()

# Combinaison de conditions (& pour ET, | pour OU) :
# Exemple : Moins de 30 ans ET salaire > 50k
jeunes_riches = df[(df['Age'] < 30) & (df['Salaire'] > 50000)]


# --- 2. Tri des données ---
# Tri simple : du plus âgé au plus jeune
df_trie = df.sort_values(by='Age', ascending=False)

# Tri multiple : d'abord par Age, puis par Salaire (pour départager)
# Utile pour classer hiérarchiquement.
df_trie_multi = df.sort_values(by=['Age', 'Salaire'], ascending=[True, False])


# --- 3. Agrégation & Statistiques ---
# Calculs globaux sur toute une colonne
moyenne_age = df['Age'].mean()
salaire_max = df['Salaire'].max()

# Agrégation par groupe (le "Pivot" de Pandas)
# Calcule le salaire moyen *pour chaque* département
salaire_par_dep = df.groupby('Departement')['Salaire'].mean()

print("Salaire moyen par département :\n", salaire_par_dep)

Ces opérations constituent le cœur du métier d’analyste :

  • Le filtrage réduit le bruit en isolant les segments intéressants.
  • Le tri (sort_values) permet d’identifier les valeurs extrêmes ou de classer les données.
  • Le groupby est l’équivalent des « Tableaux Croisés Dynamiques » (TCD) d’Excel ou du GROUP BY en SQL. C’est l’outil le plus puissant pour résumer de grands volumes de données en indicateurs clés (KPIs) par catégorie. Notez l’usage de .copy() après un filtrage : c’est une bonne habitude pour éviter le fameux avertissement SettingWithCopyWarning de Pandas si vous modifiez ces données filtrées par la suite.

NumPy : Création de Tableaux et Matrices

import numpy as np

# --- 1. Création manuelle (Listes Python vers Array NumPy) ---
# Idéal pour convertir des données brutes en format optimisé pour le calcul
matrice = np.array([
    [1, 2, 3], 
    [4, 5, 6]
])

# --- 2. Générateurs automatiques (Initialisation) ---
# Utile pour pré-allouer de la mémoire avant de remplir un tableau
vecteur_nuls = np.zeros(5)          # [0. 0. 0. 0. 0.]
matrice_uns  = np.ones((3, 3))      # Matrice 3x3 remplie de 1.

# --- 3. Séquences numériques ---
# arange : comme range() mais retourne un tableau (début, fin exclu, pas)
suite_arithmetique = np.arange(0, 10, 2)   # [0 2 4 6 8]

# linspace : découpe un intervalle en N points équidistants (début, fin inclus, nb_points)
# Indispensable pour créer l'axe X d'un graphique (ex: temps ou coordonnées)
intervalle_lisse = np.linspace(0, 1, 5)    # [0.   0.25 0.5  0.75 1.  ]

NumPy est le moteur caché sous Pandas et Scikit-Learn.
La différence clé entre arange et linspace est subtile mais importante :

  • Utilisez arange quand vous connaissez le pas entre les valeurs (ex: « tous les 2 mètres »).
  • Utilisez linspace quand vous connaissez le nombre de points que vous voulez (ex: « 5 échantillons précis entre 0 et 1 »). C’est l’outil de choix pour générer des courbes lisses en visualisation de données.

Opérations Mathématiques et Statistiques (Vectorisation)

import numpy as np

# --- 1. Opérations Élémentaires (Terme à terme) ---
# Contrairement aux listes Python, NumPy applique l'opération sur chaque élément
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])

somme = arr1 + arr2      # [5 7 9]
produit = arr1 * arr2    # [4 10 18]
division = arr1 / arr2   # [0.25 0.4 0.5]


# --- 2. Fonctions Mathématiques Avancées ---
# Appliquées instantanément à tout le tableau (très rapide)
racine = np.sqrt(arr1)
exponentiel = np.exp(arr1)
# Logarithme népérien (base e). Attention aux valeurs <= 0 !
logarithme = np.log(arr1)


# --- 3. Agrégations Statistiques ---
# Réduit le tableau à une valeur unique (scalaire)
moyenne = np.mean(arr1)       # 2.0
ecart_type = np.std(arr1)     # 0.816... (mesure la dispersion)
minimum = np.min(arr1)        # 1
maximum = np.max(arr1)        # 3

C’est ici que NumPy brille par rapport aux listes classiques : le calcul vectoriel.
Pas besoin de boucle for pour additionner deux tableaux ou calculer des racines carrées : NumPy le fait en une seule instruction, optimisée en C pour être ultra-rapide. C’est la base de tout calcul scientifique et de machine learning en Python. Notez que np.std() calcule l’écart-type de la population par défaut (diviseur N), contrairement à Pandas qui utilise l’échantillon (N-1).

Indexation et Découpage (Slicing)

import numpy as np

arr = np.array([10, 20, 30, 40, 50])

# --- 1. Indexation Positonnelle (Accès direct) ---
premier = arr[0]     # 10 (Premier élément)
dernier = arr[-1]    # 50 (Dernier élément, index négatif)


# --- 2. Slicing (Extraction de sous-ensembles) ---
# Syntaxe : [début : fin_exclue : pas]
coeur = arr[1:4]     # [20 30 40] (indices 1, 2 et 3)
debut = arr[:3]      # [10 20 30] (les 3 premiers)
fin   = arr[2:]      # [30 40 50] (à partir de l'index 2)


# --- 3. Filtrage par Masque Booléen (Conditionnel) ---
# C'est la méthode la plus puissante pour extraire des données selon une règle.

# Étape A : Créer le masque (tableau de True/False)
condition = arr > 25
# print(condition) -> [False False True True True]

# Étape B : Appliquer le masque pour filtrer
valeurs_filtrees = arr[condition]  # [30 40 50]

# Version compacte (très utilisée) :
valeurs_filtrees = arr[arr > 25]

Si l’indexation ([0]) et le slicing ([1:4]) ressemblent aux listes Python classiques, le masque booléen est une spécificité géniale de NumPy. Il permet de poser une « question » à vos données (arr > 25) et de récupérer uniquement les éléments qui répondent « Oui » (True). C’est la mécanique de base utilisée par Pandas pour filtrer des tableaux entiers en une fraction de seconde.

Visualisation : Les bases avec Matplotlib

import matplotlib.pyplot as plt
import numpy as np

# --- 1. Graphique de Ligne (Line Plot) ---
# Idéal pour montrer une évolution ou une tendance continue.

x = [1, 2, 3, 4, 5]
y = [2, 4, 6, 8, 10]

# Création de la figure (facultatif mais recommandé pour contrôler la taille)
plt.figure(figsize=(8, 5))

# Tracé de la courbe avec personnalisation (couleur, marqueurs)
plt.plot(x, y, color='blue', marker='o', linestyle='--')

# Habillage du graphique
plt.xlabel('Axe des X (Temps)')
plt.ylabel('Axe des Y (Valeurs)')
plt.title('Graphique Linéaire Simple')
plt.grid(True, alpha=0.3)  # Ajout d'une grille légère pour la lecture
plt.show()


# --- 2. Histogramme (Distribution) ---
# Idéal pour voir comment se répartissent vos données (ex: loi normale).

# Génération de 1000 points selon une loi normale (moyenne=100, écart-type=15)
donnees = np.random.normal(loc=100, scale=15, size=1000)

plt.figure(figsize=(8, 5))
# bins=30 définit la "finesse" du découpage (30 barres)
# alpha=0.7 rend les barres légèrement transparentes
plt.hist(donnees, bins=30, color='green', edgecolor='black', alpha=0.7)

plt.xlabel('Valeurs mesurées')
plt.ylabel('Nombre d\'observations')
plt.title('Distribution des données (Histogramme)')
plt.show()

Matplotlib est la bibliothèque fondatrice de visualisation en Python.

  • plt.plot() est le couteau suisse pour les courbes. L’ajout de marker='o' aide souvent à distinguer les points de données réels de la ligne interpolée.
  • plt.hist() est l’outil statistique par excellence. Il groupe vos données en « bacs » (bins) pour révéler la forme de la distribution (cloche, uniforme, asymétrique…).
    Ajouter une grille (plt.grid) et définir une taille de figure (figsize) sont des réflexes simples qui rendent vos graphiques immédiatement plus lisibles et professionnels pour un rapport.

Seaborn : Visualisation Statistique Avancée

import seaborn as sns
import matplotlib.pyplot as plt

# Configuration du style par défaut (plus esthétique que Matplotlib pur)
sns.set_theme(style="whitegrid")

# --- 1. Nuage de Points (Scatter Plot) ---
# Idéal pour chercher une relation entre deux variables numériques.
# L'argument 'hue' permet d'ajouter une 3ème dimension (ex: couleur selon le Département)
plt.figure(figsize=(8, 5))
sns.scatterplot(data=df, x='Age', y='Salaire', hue='Departement', s=100)
plt.title('Relation Âge vs Salaire')
plt.show()


# --- 2. Boîte à Moustaches (Box Plot) ---
# L'outil roi pour comparer des distributions et repérer les "outliers" (valeurs aberrantes).
plt.figure(figsize=(8, 5))
sns.boxplot(data=df, x='Departement', y='Salaire', palette="Set2")
plt.title('Distribution des Salaires par Département')
plt.show()


# --- 3. Carte de Chaleur (Heatmap) de Corrélation ---
# Indispensable pour voir quelles variables "bougent ensemble".
# Note : on filtre d'abord les colonnes numériques pour éviter les erreurs.
df_numeric = df.select_dtypes(include=['number'])
matrice_corr = df_numeric.corr()

plt.figure(figsize=(8, 6))
sns.heatmap(matrice_corr, annot=True, cmap='coolwarm', fmt=".2f", linewidths=0.5)
plt.title('Matrice de Corrélation')
plt.show()

Seaborn est construit « par-dessus » Matplotlib mais simplifie énormément le code pour les graphiques statistiques complexes.

  • Scatterplot avec hue : En une seule ligne, vous visualisez 3 variables (X, Y, et Couleur), ce qui prendrait 10 lignes en Matplotlib pur.
  • Boxplot : Résume 5 indicateurs clés par catégorie (médiane, quartiles, min/max) et isole visuellement les points extrêmes.
  • Heatmap : C’est la méthode standard pour lire une matrice de corrélation. Les couleurs chaudes (rouge) indiquent une corrélation positive forte, les froides (bleu) une négative. C’est souvent la première étape avant de faire du Machine Learning pour choisir ses variables (Feature Selection).

Pandas Plotting : Visualisation Directe

import matplotlib.pyplot as plt

# --- 1. Diagramme en Barres (Bar Chart) ---
# Idéal pour comparer des catégories (ex: ventes par produit).
# Utilise value_counts() pour compter automatiquement les occurrences.
plt.figure(figsize=(10, 6))

df['Categorie'].value_counts().plot(kind='bar', color='skyblue')

plt.title('Répartition des Ventes par Catégorie')
plt.xlabel('Catégories')
plt.ylabel('Nombre de ventes')
plt.xticks(rotation=45)  # Pivote les étiquettes si elles sont longues
plt.show()


# --- 2. Courbe Temporelle (Time Series) ---
# Indispensable pour voir une évolution.
# Astuce : Toujours convertir la colonne Date en datetime avant de tracer.
df['Date'] = pd.to_datetime(df['Date'])
df.set_index('Date')['Valeur'].plot(kind='line', figsize=(12, 5), grid=True)

plt.title('Évolution des Valeurs dans le temps')
plt.ylabel('Valeur (€)')
plt.show()


# --- 3. Diagramme Circulaire (Pie Chart) ---
# À utiliser avec parcimonie (max 5 catégories).
# autopct ajoute les % directement sur les parts.
plt.figure(figsize=(6, 6))

df['Categorie'].value_counts().plot(
    kind='pie', 
    autopct='%1.1f%%', 
    startangle=90, 
    explode=(0.1, 0, 0)  # "Détache" la 1ère part pour la mettre en valeur
)

plt.title('Parts de Marché par Catégorie')
plt.ylabel('')  # Enlève le label Y inutile sur un camembert
plt.show()

Pandas intègre directement des méthodes .plot() (basées sur Matplotlib) qui suffisent pour 90% des besoins rapides d’exploration.

  • Bar Chart : C’est le graphique le plus lisible pour comparer des quantités discrètes. L’ajout de rotation=45 est souvent nécessaire pour lire les noms longs.
  • Time Series : Pandas excelle ici. En définissant la date comme index (set_index), l’axe X est formaté intelligemment (mois, années) sans effort.
  • Pie Chart : Bien que populaire, il est souvent critiqué en Data Viz car difficile à comparer visuellement. L’option autopct est cruciale pour afficher les pourcentages exacts et rendre le graphique utile.

Analyse Exploratoire des Données (EDA)

L’EDA (Exploratory Data Analysis) est l’étape d’enquête : avant de modéliser, on doit « faire parler » les données.

Objectifs de l’EDA

  1. Auditer la qualité (données manquantes, types incorrects).
  2. Comprendre la distribution des variables (normalité, asymétrie).
  3. Détecter les signaux faibles (corrélations) et les anomalies (outliers).

Le Script Complet d’EDA

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

# --- Étape 1 : Chargement & Audit Macro ---
# Vision globale de la structure du fichier
df = pd.read_csv('donnees.csv')

print("--- INFORMATIONS GÉNÉRALES ---")
df.info()  # Types des colonnes et mémoire utilisée
print("\n--- APERÇU ---")
print(df.head()) # Vérifier visuellement le format


# --- Étape 2 : Hygiène des Données (Valeurs manquantes) ---
# Identifier les colonnes "à trous" qui nécessiteront un nettoyage
missing_data = df.isnull().sum()
missing_only = missing_data[missing_data > 0] # Filtre pour n'afficher que les problèmes

if not missing_only.empty:
    print("\n--- VALEURS MANQUANTES ---")
    print(missing_only)
    # Visualisation des manques (barres blanches = données manquantes)
    plt.figure(figsize=(10, 6))
    sns.heatmap(df.isnull(), cbar=False, yticklabels=False, cmap='viridis')
    plt.title('Carte des valeurs manquantes')
    plt.show()
else:
    print("\n✅ Aucune valeur manquante détectée.")


# --- Étape 3 : Analyse Univariée (Distributions) ---
# Comprendre chaque variable isolément.
# Les histogrammes révèlent si les données suivent une loi normale (cloche) ou sont biaisées.
df.hist(bins=30, figsize=(15, 10), layout=(3, 3), grid=False)
plt.suptitle('Distribution des Variables Numériques', fontsize=16)
plt.tight_layout() # Ajuste automatiquement l'espacement
plt.show()


# --- Étape 4 : Analyse Multivariée (Corrélations) ---
# Comprendre les liens entre variables.
# Note : On ne garde que les colonnes numériques pour la corrélation
df_num = df.select_dtypes(include=['number'])

plt.figure(figsize=(10, 8))
sns.heatmap(df_num.corr(), annot=True, cmap='coolwarm', fmt=".2f", vmin=-1, vmax=1)
plt.title('Matrice de Corrélation (Heatmap)')
plt.show()

Ce workflow suit une logique d’entonnoir :

  • On commence par la structure (infoisnull) pour voir si le « terrain » est propre. La visualisation des valeurs manquantes par heatmap est une technique très efficace pour repérer des blocs de données perdus.
  • Ensuite, on regarde chaque variable seule (histogrammes). layout et tight_layout sont des astuces Matplotlib pour que les graphiques ne se chevauchent pas.
  • Enfin, on regarde les relations (corrélation). Fixer vmin=-1 et vmax=1 dans la heatmap garantit que l’échelle de couleur est correcte (le bleu foncé sera vraiment -1 et le rouge vif +1), évitant des interprétations trompeuses sur des corrélations faibles.

Techniques Avancées d’EDA (Exploratory Data Analysis)

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np

# --- 1. Visualisation Multidimensionnelle (Pairplot) ---
# Le "couteau suisse" de l'exploration : affiche la relation entre CHAQUE paire de variables.
# L'argument 'hue' permet de colorer les points selon une catégorie (ex: segments clients).
# corner=True (optionnel) supprime le triangle supérieur redondant pour plus de clarté.
sns.pairplot(df, hue='Categorie', diag_kind='kde', corner=True)
plt.suptitle('Vue d\'ensemble des relations par paire', y=1.02) # Titre légèrement décalé vers le haut
plt.show()


# --- 2. Détection Statistique des Outliers (Méthode IQR) ---
# Identification des valeurs extrêmes via l'Interquartile Range.
# Utile pour nettoyer les erreurs de saisie ou isoler les cas exceptionnels.

# On ne travaille que sur les colonnes numériques
df_num = df.select_dtypes(include=[np.number])

Q1 = df_num.quantile(0.25) # 1er Quartile (25%)
Q3 = df_num.quantile(0.75) # 3ème Quartile (75%)
IQR = Q3 - Q1              # Écart interquartile

# Définition des bornes (règle standard de Tukey : 1.5 * IQR)
borne_inf = Q1 - 1.5 * IQR
borne_sup = Q3 + 1.5 * IQR

# Création d'un masque : True si la ligne contient AU MOINS une valeur hors normes
# any(axis=1) signifie "regarder ligne par ligne"
masque_outliers = ((df_num < borne_inf) | (df_num > borne_sup)).any(axis=1)

outliers = df[masque_outliers]
print(f"Nombre de lignes contenant des outliers : {len(outliers)}")
# print(outliers.head())


# --- 3. Distribution Cumulative (CDF) ---
# Permet de répondre à des questions type : "Quel % des clients dépense moins de X ?"
# C'est souvent plus lisible qu'un histogramme classique pour voir des seuils.

df_num.hist(
    cumulative=True, 
    density=True,     # Normalise l'axe Y de 0 à 1 (soit 0% à 100%)
    bins=50, 
    alpha=0.7, 
    figsize=(12, 8),
    color='purple',
    edgecolor='black'
)

plt.suptitle('Fonctions de Répartition Cumulative (CDF)', fontsize=16)
plt.tight_layout()
plt.show()

Ces trois techniques répondent à des besoins précis :

  1. Le Pairplot est souvent la première chose qu’un Data Scientist lance sur un dataset propre (moins de 10-15 variables) pour « voir » les clusters ou les linéarités immédiatement.
  2. La méthode IQR est robuste car elle ne dépend pas de la moyenne (qui est sensible aux extrêmes), mais de la médiane et des quartiles. C’est le standard industriel pour le nettoyage automatique.
  3. L’histogramme cumulatif (avec density=True) transforme l’axe Y en probabilité (0 à 1). Si la courbe monte très vite au début, cela signifie que la majorité de vos données sont concentrées sur les petites valeurs. C’est crucial pour comprendre la concentration (type Loi de Pareto).

Nettoyage de Données (Data Cleaning) : Identification des Problèmes

import pandas as pd
import numpy as np

# --- 1. Audit des Valeurs Manquantes (Missing Values) ---
# Compter les valeurs nulles (NaN) par colonne
missing_count = df.isnull().sum()

# Calculer le pourcentage de manques (plus parlant que le nombre brut)
missing_pct = df.isnull().mean() * 100

# Afficher uniquement les colonnes problématiques (> 0%)
print("--- Pourcentage de valeurs manquantes ---")
print(missing_pct[missing_pct > 0].sort_values(ascending=False))


# --- 2. Gestion des Doublons (Duplicates) ---
# Vérifier si des lignes entières sont identiques
nb_doublons = df.duplicated().sum()
print(f"\nNombre de doublons exacts : {nb_doublons}")

if nb_doublons > 0:
    # Isoler les doublons pour inspection (keep=False montre toutes les copies)
    doublons_visibles = df[df.duplicated(keep=False)]
    # Pour les supprimer directement :
    # df.drop_duplicates(inplace=True)


# --- 3. Détection des Valeurs Aberrantes (Outliers) ---
# Fonction générique basée sur l'écart interquartile (IQR)
def get_outliers_iqr(df_in, col_name):
    """
    Retourne les lignes considérées comme outliers pour une colonne donnée
    selon la méthode de Tukey (1.5 * IQR).
    """
    # Vérification de sécurité : la colonne doit être numérique
    if not np.issubdtype(df_in[col_name].dtype, np.number):
        return pd.DataFrame() # Retourne vide si non numérique

    Q1 = df_in[col_name].quantile(0.25)
    Q3 = df_in[col_name].quantile(0.75)
    IQR = Q3 - Q1
    
    bor_inf = Q1 - 1.5 * IQR
    bor_sup = Q3 + 1.5 * IQR
    
    # Masque booléen
    masque = (df_in[col_name] < bor_inf) | (df_in[col_name] > bor_sup)
    return df_in[masque]

# Exemple d'utilisation sur une colonne spécifique
outliers_salaire = get_outliers_iqr(df, 'Salaire')
print(f"\nOutliers détectés dans 'Salaire' : {len(outliers_salaire)}")

Ce script couvre les trois piliers du nettoyage :

  1. Valeurs manquantes : Le pourcentage est souvent plus utile que le nombre absolu. Si une colonne a 90% de vide, elle est probablement inutilisable.
  2. Doublons : duplicated() repère les lignes identiques. L’option keep=False est une astuce pour voir toutes les occurrences du doublon (l’original et la copie), ce qui permet de comprendre pourquoi ils sont là (bug d’export, erreur de saisie…).
  3. Outliers (IQR) : La fonction proposée ici est sécurisée (elle vérifie le type numérique) et isolée, ce qui permet de l’appliquer colonne par colonne ou dans une boucle sur toutes les variables numériques.

Traitement des Valeurs Manquantes (Imputation)

ne fois les manques identifiés, il faut décider : supprimer ou remplacer ?

import pandas as pd
from sklearn.impute import SimpleImputer

# --- 1. Suppression (Radicale) ---
# À utiliser uniquement si vous avez énormément de données ou très peu de manques.

# Supprime toute ligne contenant AU MOINS une valeur manquante
df_drop_rows = df.dropna()

# Supprime toute colonne contenant des valeurs manquantes (rarement utilisé, trop destructeur)
df_drop_cols = df.dropna(axis=1)


# --- 2. Imputation Simple avec Pandas ---
# Note : La méthode moderne évite "inplace=True" (futur déprécié) au profit de l'assignation.

# Remplacement par la moyenne (pour les données numériques sans outliers majeurs)
df['Age'] = df['Age'].fillna(df['Age'].mean())

# Remplacement par une constante (pour les catégories ou textes)
df['Nom'] = df['Nom'].fillna('Inconnu')

# Propagation de la dernière valeur valide (Forward Fill)
# Utile pour les séries temporelles (ex: cours de bourse manquant un jour férié)
df['Categorie'] = df['Categorie'].ffill()


# --- 3. Imputation Robuste avec Scikit-Learn ---
# Recommandé pour les pipelines de Machine Learning (reproductible).

# Création de l'imputeur (stratégie : moyenne, médiane, mode ou constante)
# La médiane est souvent préférée à la moyenne car moins sensible aux valeurs extrêmes.
imputer = SimpleImputer(strategy='median')

cols_to_impute = ['Age', 'Salaire']

# fit_transform calcule la médiane ET remplace les trous en une fois
# Attention : cela renvoie un tableau Numpy, il faut le remettre dans le DataFrame
df[cols_to_impute] = imputer.fit_transform(df[cols_to_impute])

print("Imputation terminée.")

Choisir la bonne méthode est une question de contexte :

  • dropna() est la solution de facilité, mais dangereuse sur de petits jeux de données.
  • fillna() est parfait pour du nettoyage rapide « one-shot ». Notez l’usage de .ffill() (forward fill) qui est la méthode standard pour boucher les trous dans des données ordonnées temporellement.
  • SimpleImputer de Scikit-Learn est plus verbeux mais indispensable si vous faites du Machine Learning. Pourquoi ? Parce qu’il stocke la valeur de remplacement (la médiane calculée sur les données d’entraînement) pour pouvoir l’appliquer plus tard à de nouvelles données de test, garantissant ainsi la cohérence du modèle.

Mise à l’Échelle des Données (Scaling)

Beaucoup d’algorithmes (K-Means, KNN, Réseaux de neurones) sont sensibles à l’échelle des données. Transformer les variables pour qu’elles aient le même ordre de grandeur est donc essentiel.

import pandas as pd
from sklearn.preprocessing import MinMaxScaler, StandardScaler

# Sélection des colonnes à transformer
cols_to_scale = ['Age', 'Salaire']

# --- 1. Min-Max Scaling (Normalisation) ---
# Ramène toutes les valeurs entre 0 et 1.
# Formule : (X - X_min) / (X_max - X_min)
# Sensible aux outliers !
min_max_scaler = MinMaxScaler()

# On crée de nouvelles colonnes pour comparer avant/après
# fit_transform calcule les min/max et applique la transformation
df_norm = df.copy()
df_norm[cols_to_scale] = min_max_scaler.fit_transform(df[cols_to_scale])

print("Données normalisées (0-1) :\n", df_norm.head())


# --- 2. Standardisation (Z-Score) ---
# Centre les données autour de 0 avec un écart-type de 1.
# Formule : (X - Moyenne) / Ecart-Type
# Plus robuste aux outliers, standard pour la plupart des modèles de ML.
std_scaler = StandardScaler()

df_std = df.copy()
df_std[cols_to_scale] = std_scaler.fit_transform(df[cols_to_scale])

print("\nDonnées standardisées (Centrées-Réduites) :\n", df_std.head())

Bien que les deux méthodes rapprochent les valeurs, leur usage diffère :

  • MinMaxScaler écrase tout dans l’intervalle [0, 1]. C’est utile pour des algorithmes qui attendent strictement cette plage (comme le Deep Learning) ou quand la distribution n’est pas gaussienne.
  • StandardScaler ne borne pas les valeurs (vous pouvez avoir -3 ou +5), mais il change la forme de la distribution pour qu’elle ait une moyenne de 0 et une variance unitaire. C’est le choix par défaut pour la régression linéaire, la régression logistique et les SVM, car ces modèles supposent souvent que les données sont « normalement » distribuées.

Statistiques Descriptives : Tendance Centrale

import matplotlib.pyplot as plt

# --- 1. Calcul des Indicateurs ---

# La Moyenne (Mean) : Sensible aux valeurs extrêmes
moyenne = df['Valeur'].mean()

# La Médiane (Median) : Valeur centrale (50% en dessous, 50% au-dessus)
# C'est l'indicateur "robuste" par excellence (ex: salaire médian vs moyen).
mediane = df['Valeur'].median()

# Le Mode : Valeur la plus fréquente (surtout pour les données catégorielles)
# .mode() renvoie une Série car il peut y avoir plusieurs modes, on prend le premier [0].
mode_val = df['Categorie'].mode()[0]

print(f"Moyenne : {moyenne:.2f} | Médiane : {mediane:.2f} | Mode : {mode_val}")


# --- 2. Comparaison Visuelle (Histogramme + Repères) ---
# Ce graphique est le meilleur moyen de détecter une "asymétrie" (skewness).

plt.figure(figsize=(10, 6))

# Histogramme de fond
df['Valeur'].hist(bins=30, color='skyblue', alpha=0.7, edgecolor='white', label='Distribution')

# Lignes verticales pour les indicateurs
plt.axvline(moyenne, color='red', linestyle='--', linewidth=2, label=f'Moyenne ({moyenne:.2f})')
plt.axvline(mediane, color='green', linestyle='-', linewidth=2, label=f'Médiane ({mediane:.2f})')

plt.title('Moyenne vs Médiane : Détection de l\'asymétrie')
plt.legend()
plt.show()

Ce script permet de visualiser un concept statistique fondamental :
Si la Moyenne (rouge) et la Médiane (vert) sont superposées, votre distribution est symétrique (type courbe en cloche).
Si elles s’éloignent, la distribution est biaisée.

  • Exemple classique : Dans les salaires, quelques milliardaires tirent la moyenne vers le haut (à droite), alors que la médiane reste ancrée sur le « vrai » salaire du milieu. C’est pourquoi on dit souvent que la médiane est plus représentative de la réalité pour des distributions inégales.

Statistiques Descriptives : Mesures de Dispersion

# --- 1. Variance et Écart-Type (Standard Deviation) ---
# Mesurent la dispersion moyenne autour de la moyenne.
# Note : Pandas calcule par défaut l'écart-type d'échantillon (ddof=1)
variance = df['Valeur'].var()
ecart_type = df['Valeur'].std()

# Le Coefficient de Variation (CV) permet de comparer la dispersion 
# de deux variables ayant des unités différentes (ex: prix en € vs poids en kg).
cv = (ecart_type / df['Valeur'].mean()) * 100
print(f"Coefficient de Variation : {cv:.2f}% (Plus c'est élevé, plus c'est hétérogène)")


# --- 2. Quartiles et IQR (Approche Robuste) ---
# Découpe la population en 4 parts égales.
quartiles = df['Valeur'].quantile([0.25, 0.5, 0.75])
print("\nQuartiles :\n", quartiles)

Q1 = quartiles[0.25] # 25% des données sont en dessous
Q3 = quartiles[0.75] # 75% des données sont en dessous

# L'Écart Interquartile (IQR) mesure la dispersion des 50% de valeurs centrales.
# C'est la "largeur" de la boîte dans un Boxplot.
IQR = Q3 - Q1
print(f"IQR (Cœur de la distribution) : {IQR:.2f}")


# --- 3. Résumé complet (La méthode facile) ---
# Affiche tout ça en une ligne
print("\nRésumé Statistique :")
print(df['Valeur'].describe())

Ces indicateurs répondent à la question : « Est-ce que mes données se ressemblent toutes ? »

  • L’Écart-Type est facile à comprendre (c’est la « marge d’erreur » moyenne), mais il explose s’il y a une seule valeur extrême.
  • L’IQR (Interquartile Range) est plus fiable. Il ignore les 25% les plus petits et les 25% les plus grands pour se concentrer sur la « classe moyenne » des données.
  • Le CV (Coefficient de Variation) est génial pour comparer : un CV de 15% sur des tailles d’humains signifie que c’est très homogène, alors qu’un CV de 150% sur des patrimoines indique une inégalité massive.

Analyse Bivariée : Corrélation et Covariance

Cette étape mesure la « force » du lien entre deux variables quantitatives.

import numpy as np
from scipy.stats import pearsonr

# --- 1. La Corrélation (Pearson) ---
# Mesure la relation linéaire entre deux variables.
# -1 = inverse (plus l'une monte, plus l'autre descend)
# 0 = aucune relation
# +1 = parfaite (plus l'une monte, plus l'autre monte)
correlation_simple = df['Variable1'].corr(df['Variable2'])
print(f"Coefficient de Corrélation : {correlation_simple:.2f}")


# --- 2. La Covariance ---
# Similaire à la corrélation mais dépend de l'échelle des données.
# Difficile à interpréter directement, mais utile pour certains calculs (PCA).
covariance = df['Variable1'].cov(df['Variable2'])


# --- 3. Test de Significativité (p-value) ---
# Question cruciale : "Cette corrélation est-elle réelle ou due au hasard ?"
# On utilise le test de Pearson de SciPy.
corr_coef, p_value = pearsonr(df['Variable1'], df['Variable2'])

print(f"\nRésultat du Test de Pearson :")
print(f"- Corrélation : {corr_coef:.3f}")
print(f"- P-value : {p_value:.5f}")

# Interprétation automatique
seuil = 0.05  # Standard scientifique (5% de risque d'erreur)
if p_value < seuil:
    print("✅ La corrélation est statistiquement SIGNIFICATIVE (rejet de H0).")
else:
    print("❌ La corrélation n'est pas significative (peut être due au hasard).")

Il ne faut jamais regarder le coefficient de corrélation (r) seul.

  • Un r = 0.8 semble génial, mais si vous n’avez que 5 points de données, la p-value sera probablement élevée (> 0.05), ce qui veut dire « attention, c’est peut-être juste un coup de chance ».
  • À l’inverse, avec 1 million de lignes, même une corrélation minuscule de 0.05 peut avoir une p-value minuscule, ce qui signifie « le lien est faible, mais il existe vraiment ».
  • La Covariance est moins utilisée en analyse directe car elle n’est pas bornée (elle peut valoir 1000 ou 0.001 selon vos unités), contrairement à la corrélation qui est toujours entre -1 et 1.

Travail avec Différents Formats de Données

Savoir jongler entre les formats (CSV, Excel, JSON, SQL) est le quotidien du Data Analyst.

import pandas as pd
import json
import sqlite3

# --- 1. Fichiers CSV (Le standard) ---
# Lecture "Robuste" : Gestion des spécificités françaises (virgule décimale, point-virgule)
# na_values aide Pandas à reconnaître les différentes façons d'écrire "vide".
df_csv = pd.read_csv('donnees.csv', 
                     delimiter=';',       # Souvent ';' en France
                     decimal=',',         # Virgule pour les décimales
                     parse_dates=['Date'],# Convertit automatiquement en datetime
                     na_values=['N/A', 'NULL', 'nan', ''])

# Écriture : index=False évite de créer une colonne inutile pour les numéros de ligne
df_csv.to_csv('resultats_clean.csv', index=False, sep=';', encoding='utf-8')


# --- 2. Fichiers Excel (Le format métier) ---
# Lecture simple d'un onglet spécifique
df_excel = pd.read_excel('donnees.xlsx', sheet_name='Feuil1')

# Écriture multi-onglets : Indispensable pour les rapports complets
# Utilise le contexte 'with' pour fermer proprement le fichier après écriture
with pd.ExcelWriter('rapport_final.xlsx', engine='openpyxl') as writer:
    df_csv.head(10).to_excel(writer, sheet_name='Résumé', index=False)
    df_excel.to_excel(writer, sheet_name='Données Complètes', index=False)


# --- 3. Fichiers JSON (Le format Web/API) ---
# Lecture simple si le format est "plat"
df_json = pd.read_json('donnees.json')

# Lecture de JSON complexe (imbriqué/nested)
# json_normalize "aplatit" la structure pour en faire un tableau 2D
with open('donnees_complexes.json', 'r', encoding='utf-8') as f:
    data_brute = json.load(f)
    
df_flat = pd.json_normalize(data_brute, sep='_') # ex: user_id, user_name
df_flat.to_json('resultats_flat.json', orient='records', force_ascii=False)


# --- 4. Bases de Données (SQL) ---
# Connexion à une base SQLite (incluse dans Python)
# Pour PostgreSQL ou MySQL, utilisez 'sqlalchemy' (engine = create_engine(...))
conn = sqlite3.connect('mon_entreprise.db')

try:
    # Lecture : On écrit directement la requête SQL, Pandas gère le reste
    query = "SELECT nom, email FROM clients WHERE age > 25"
    df_sql = pd.read_sql_query(query, conn)
    
    # Écriture : Création d'une nouvelle table
    # if_exists='replace' (écrase), 'append' (ajoute), 'fail' (erreur si existe)
    df_sql.to_sql('clients_cibles', conn, if_exists='replace', index=False)
    print("Table SQL mise à jour avec succès.")
finally:
    conn.close() # Toujours fermer la connexion

Projets Pratiques

Projet 1 :  Analyse de Ventes (Retail)

Ce script simule un cas réel : charger des logs de ventes, nettoyer les dates, agréger par période et identifier les best-sellers.

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# Configuration esthétique
sns.set_theme(style="whitegrid")

# --- 1. Chargement & Préparation ---
# On imagine un CSV avec : Date, Produit, Categorie, Montant, Quantite
try:
    ventes = pd.read_csv('ventes.csv')
    print("Données chargées :", ventes.shape)
except FileNotFoundError:
    # Création de données factices pour l'exemple si le fichier n'existe pas
    data = {
        'Date': pd.date_range(start='2024-01-01', periods=100, freq='D'),
        'Produit': ['Laptop', 'Souris', 'Clavier', 'Écran', 'Casque'] * 20,
        'Montant': [1200, 25, 45, 300, 80] * 20
    }
    ventes = pd.DataFrame(data)
    print("⚠️ Fichier non trouvé, utilisation de données de test.")


# --- 2. Nettoyage & Feature Engineering ---
# Conversion impérative en datetime pour manipuler le temps
ventes['Date'] = pd.to_datetime(ventes['Date'])

# Suppression des lignes vides (sécurité)
ventes_clean = ventes.dropna().copy()

# Extraction du Mois (Format YYYY-MM) pour l'agrégation
ventes_clean['Mois'] = ventes_clean['Date'].dt.to_period('M')


# --- 3. Analyse Temporelle (Trend) ---
# GroupBy sur le Mois pour voir l'évolution du chiffre d'affaires (CA)
ca_mensuel = ventes_clean.groupby('Mois')['Montant'].sum()

# Visualisation
plt.figure(figsize=(12, 6))
# Astuce : convertir l'index (Period) en string ou timestamp pour que Matplotlib gère bien l'axe X
ca_mensuel.plot(kind='line', marker='o', color='#2c3e50', linewidth=2)

plt.title('Évolution du Chiffre d\'Affaires Mensuel', fontsize=14)
plt.xlabel('Période')
plt.ylabel('CA Total (€)')
plt.grid(True, linestyle='--', alpha=0.7)
plt.tight_layout()
plt.show()


# --- 4. Analyse Produit (Pareto) ---
# Quels produits rapportent le plus ?
top_produits = ventes_clean.groupby('Produit')['Montant'].sum().sort_values(ascending=False)

# Visualisation des Top 5
plt.figure(figsize=(10, 5))
sns.barplot(x=top_produits.head(5).values, y=top_produits.head(5).index, palette="viridis")

plt.title('Top 5 Produits par Chiffre d\'Affaires')
plt.xlabel('Montant cumulé (€)')
plt.show()

print("\n--- Résumé ---")
print(f"Total Ventes : {ventes_clean['Montant'].sum():,.2f} €")
print(f"Meilleur Mois : {ca_mensuel.idxmax()} ({ca_mensuel.max():,.2f} €)")

Dans ce mini-projet, l’étape clé est dt.to_period('M'). Contrairement à une simple extraction de mois (1 à 12), cela garde l’année (ex: « 2024-01 »). C’est vital si vos données couvrent plusieurs années, pour ne pas mélanger janvier 2024 et janvier 2025.
L’ajout du Barplot horizontal pour les produits est souvent plus lisible qu’une liste textuelle, surtout pour présenter vos résultats à des collègues non-techniques.

Projet Pratique 2 : Analyse de Satisfaction Client (Test A/B)

Ce script va au-delà de la moyenne : il vérifie scientifiquement si une différence de satisfaction entre deux régions est réelle ou due au hasard.

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from scipy import stats

# --- 1. Chargement & Préparation ---
try:
    df = pd.read_csv('satisfaction_clients.csv')
except FileNotFoundError:
    # Données factices pour la démo
    np.random.seed(42)
    df = pd.DataFrame({
        'ID': range(200),
        'Region': np.random.choice(['Nord', 'Sud'], 200),
        'Categorie': np.random.choice(['Premium', 'Standard'], 200),
        'Score_Satisfaction': np.random.normal(7, 1.5, 200).clip(0, 10), # Note sur 10
        'Temps_Reponse': np.random.normal(24, 5, 200) # Heures
    })
    # On biaise artificiellement le Sud pour l'exemple
    df.loc[df['Region'] == 'Sud', 'Score_Satisfaction'] += 1

print("Aperçu des données :\n", df.head())


# --- 2. Analyse Descriptive par Groupe ---
print("\n--- Scores Moyens ---")
# On groupe par deux critères pour plus de finesse
resume = df.groupby(['Region', 'Categorie'])['Score_Satisfaction'].agg(['mean', 'count'])
print(resume)

# Visualisation des distributions (Boxplot)
plt.figure(figsize=(8, 5))
sns.boxplot(data=df, x='Region', y='Score_Satisfaction', palette="Set3")
plt.title('Distribution des Scores de Satisfaction par Région')
plt.show()


# --- 3. Test Statistique (Test de Student / T-test) ---
# Objectif : Savoir si la différence entre Nord et Sud est significative.

groupe_nord = df[df['Region'] == 'Nord']['Score_Satisfaction']
groupe_sud = df[df['Region'] == 'Sud']['Score_Satisfaction']

# Test t pour échantillons indépendants
t_stat, p_value = stats.ttest_ind(groupe_nord, groupe_sud, equal_var=False)

print(f"\n--- Résultat du T-Test (Nord vs Sud) ---")
print(f"Statistique T : {t_stat:.3f}")
print(f"P-value       : {p_value:.5f}")

if p_value < 0.05:
    print("✅ Résultat SIGNIFICATIF : Il y a une vraie différence de satisfaction entre les régions.")
else:
    print("❌ Résultat NON significatif : La différence observée peut être due au hasard.")


# --- 4. Facteurs d'Influence (Corrélation) ---
# Qu'est-ce qui joue sur la satisfaction ? (ex: le temps de réponse)
df_num = df.select_dtypes(include=[np.number])
corr = df_num.corr()

plt.figure(figsize=(6, 5))
sns.heatmap(corr[['Score_Satisfaction']].sort_values(by='Score_Satisfaction', ascending=False),
            annot=True, cmap='coolwarm', vmin=-1, vmax=1)
plt.title('Corrélation avec la Satisfaction')
plt.show()

L’analyse de satisfaction ne doit jamais se limiter à dire « La région B est à 7.5/10 et la A à 7.2/10 ».
Le T-test (ou Test de Student) est l’outil mathématique pour valider cette différence. Ici, l’option equal_var=False (aussi appelé test de Welch) rend le test plus robuste si les variances des deux groupes sont différentes (ce qui est souvent le cas dans la réalité).
Enfin, le Boxplot complète visuellement le test : il montre non seulement la moyenne, mais aussi si les notes sont très dispersées ou homogènes.

Projet Pratique 3 : Prévision de Tendances (Trend Forecasting)

Ce script utilise la régression linéaire pour prédire une valeur future en fonction du temps.

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression

# --- 1. Génération de données (Simulation d'une tendance à la hausse avec saisonnalité) ---
dates = pd.date_range(start='2023-01-01', periods=365, freq='D')
values = np.linspace(50, 150, 365) + np.sin(np.linspace(0, 20, 365)) * 10 + np.random.normal(0, 5, 365)
df = pd.DataFrame({'Date': dates, 'Valeur': values})

# --- 2. Feature Engineering ---
# On transforme la date en nombres exploitables par la régression
df['Ordinal_Date'] = df['Date'].map(pd.Timestamp.toordinal)
df['Jour_Annee'] = df['Date'].dt.dayofyear

# --- 3. Séparation Temporelle (Train/Test) ---
# IMPORTANT : Pour des séries temporelles, on ne mélange PAS (shuffle=False).
# On entraîne sur le passé (janvier-octobre) pour prédire le futur (novembre-décembre).
split_index = int(len(df) * 0.8)

train = df.iloc[:split_index]
test = df.iloc[split_index:]

# Variables explicatives (X) et cible (y)
features = ['Ordinal_Date']
X_train = train[features]
y_train = train['Valeur']
X_test = test[features]
y_test = test['Valeur']


# --- 4. Modélisation ---
model = LinearRegression()
model.fit(X_train, y_train)

# Prédictions
pred_train = model.predict(X_train)
pred_test = model.predict(X_test)


# --- 5. Visualisation (Courbe continue) ---
plt.figure(figsize=(12, 6))

# Données réelles
plt.plot(df['Date'], df['Valeur'], label='Données Réelles', color='lightgray', linewidth=2)

# Modèle sur l'entraînement (Passé)
plt.plot(train['Date'], pred_train, label='Tendance modélisée (Train)', color='blue', linestyle='--')

# Prédictions sur le test (Futur)
plt.plot(test['Date'], pred_test, label='Prévision (Test)', color='red', linewidth=2)

plt.title('Prévision de Tendance Linéaire')
plt.xlabel('Date')
plt.ylabel('Valeur')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()


# --- 6. Évaluation ---
r2_score = model.score(X_test, y_test)
print(f"Qualité du modèle (R²) sur les données futures : {r2_score:.2f}")
# Note : Un R² bas n'est pas forcément grave sur une série temporelle complexe, 
# cela veut dire que la régression capture la tendance globale mais pas les oscillations saisonnières.

Conclusion & Perspectives

Félicitations ! Vous possédez désormais la boîte à outils essentielle du Data Analyst en Python.

Récapitulatif des Compétences Acquises

  • Wrangling : Vous savez dompter des données brutes avec Pandas (nettoyage, fusion, transformation).
  • Data Viz : Vous pouvez raconter une histoire visuelle claire grâce à Seaborn et Matplotlib.
  • Analyse Statistique : Vous savez dépasser la simple moyenne pour interroger la fiabilité des données (corrélations, T-test, distributions).
  • Rigueur : Vous avez appris à structurer vos projets (environnements virtuels, gestion des erreurs).

Prochaines Étapes : Où aller maintenant ?

Le monde de la Data est vaste. Voici les pistes naturelles de progression :

  1. Vers le Machine Learning (Data Scientist)
    • Approfondissez Scikit-Learn pour la classification (prévoir un churn client) et le clustering (segmenter des marchés).
  2. Vers le Big Data (Data Engineer)
    • Si vos fichiers Excel explosent, regardez du côté de PySpark ou Dask pour traiter des millions de lignes en parallèle.
    • Apprenez SQL en profondeur, c’est la langue universelle des bases de données.
  3. Vers la Business Intelligence (BI)
    • Python est génial pour l’analyse, mais pour les tableaux de bord interactifs partagés en entreprise, connectez vos scripts à Power BI ou Tableau.
  4. L’Industrialisation (DevOps/MLOps)
    • Apprenez à versionner votre code avec Git (GitHub/GitLab).
    • Automatisez vos scripts pour qu’ils tournent tous les matins sans vous.

Les 5 Commandements du Data Analyst

  1. Curieux tu seras : Ne fais pas confiance aux données aveuglément, cherche toujours l’anomalie.
  2. Reproductible tu resteras : Ton code doit pouvoir être relancé par un collègue dans 6 mois et donner le même résultat.
  3. Simple tu feras : Une visualisation simple vaut mieux qu’un graphique 3D illisible.
  4. Sceptique tu demeureras : « Corrélation n’est pas causalité ». Vérifie toujours tes hypothèses.
  5. Pratique tu privilégieras : La théorie est belle, mais rien ne vaut l’analyse d’un vrai dataset « sale » et incomplet (Kaggle est une excellente mine d’or pour s’entraîner).

La route est longue, mais vous avez maintenant le véhicule pour l’emprunter. Bon code !