Cet exercice teste la manipulation de données avec pandas dans un cas d'analyse réaliste. En trois questions progressives, il révèle si le candidat pense « vectorisé », vérifie ses données et sait passer d'un besoin métier à un résultat. Corrigé et signaux inclus.
Le fil rouge : chercher les réflexes data, pas la mémoire de la syntaxe. Un bon candidat vérifie ses données, évite les boucles inutiles et sait expliquer ce que fait chaque ligne.
Deux DataFrames fournis au candidat.
Un cas e-commerce simple : un DataFrame de commandes et un de clients. Le candidat travaille sur ces deux tables, sans données réelles à charger.
commandes : colonnes = [id, client_id, montant, date_commande, statut]
clients : colonnes = [id, pays, date_inscription]Calcule le chiffre d'affaires par mois, en ne gardant que les commandes payées.
L'entrée en matière : filtrer, extraire le mois d'une date et agréger. On regarde surtout si le candidat vérifie le type de la colonne date avant de l'utiliser.
import pandas as pd
commandes["date_commande"] = pd.to_datetime(commandes["date_commande"])
ca_mensuel = (
commandes[commandes["statut"] == "payee"]
.groupby(commandes["date_commande"].dt.to_period("M"))["montant"]
.sum()
)Quel est le CA payé et le nombre de clients distincts par pays ?
La jointure entre les deux DataFrames, puis une double agrégation. Le piège classique : compter les commandes au lieu des clients distincts.
df = commandes[commandes["statut"] == "payee"].merge(
clients, left_on="client_id", right_on="id", suffixes=("", "_client"))
resultat = df.groupby("pays").agg(
ca=("montant", "sum"),
clients=("client_id", "nunique"),
)Repère les clients dont le montant moyen de commande dépasse largement la moyenne globale.
La question ouverte qui révèle l'esprit critique : il faut définir « largement », gérer les cas limites et ne pas conclure sur un client à une seule commande.
moyenne_par_client = (
commandes[commandes["statut"] == "payee"]
.groupby("client_id")
.agg(moyenne=("montant", "mean"), n=("id", "count"))
)
seuil = 2 * commandes.loc[commandes["statut"] == "payee", "montant"].mean()
anormaux = moyenne_par_client[
(moyenne_par_client["moyenne"] > seuil) & (moyenne_par_client["n"] >= 3)
]Signal d'alerte : ce qui distingue un senior : il ne se contente pas de sortir une liste, il questionne — « est-ce un vrai signal ou un client à une seule grosse commande ? ». Cet esprit critique vaut plus que la syntaxe.
| Niveau | Maîtrise attendue | Signal GO | NO-GO |
|---|---|---|---|
| Junior | Réussit Q1 | Filtre, convertit la date, agrège | Boucle au lieu de vectoriser |
| Confirmé | Réussit Q2 | Joint et utilise nunique() | Compte les commandes au lieu des clients |
| Senior | Réussit Q3 avec un seuil justifié | Gère les cas limites, questionne le résultat | Livre une liste sans esprit critique |
| Lead | Explique clairement sa démarche | Vulgarise et challenge ses propres résultats | Répond juste sans savoir expliquer |
Data Builder mène l'entretien technique et vous livre un rapport clair et détaillé sous 24h. Premier entretien offert.