Une première analyse avec pandas tient en quatre gestes : charger le fichier, vérifier ce que pandas en a compris, poser une question, contrôler la réponse à la main. Sur un relevé de températures par salle, « quelle salle est la plus chaude ? » se règle en une ligne : df.groupby("salle")["temperature"].mean(). Cette ligne ne vaut rien si le fichier a été mal lu, et c'est là que se cachent les erreurs des débuts. Tout se joue ici sur un fichier de huit lignes, que tu peux vérifier de tête.
Charger un CSV écrit à la française
La bibliothèque pandas est un ensemble d'outils que tu importes dans ton code Python. Elle range les données dans un DataFrame, un tableau aux colonnes nommées, avec un type de données par colonne.
Voici releves.csv (données fictives), ouvert dans un éditeur de texte :
salle;jour;temperature
A101;lundi;19,5
A101;mardi;20,1
A101;mercredi;19,8
B204;lundi;22,4
B204;mardi;
B204;mercredi;21,8
C010;lundi;17,8
C010;mardi;18,4
Un CSV (comma-separated values, « valeurs séparées par des virgules ») est un fichier texte : une ligne par ligne du tableau, un séparateur entre les colonnes. En France, la virgule sert déjà aux décimales : un fichier qui l'emploie ainsi sépare ses colonnes autrement, ici par des points-virgules. Par défaut, pandas attend des virgules entre les colonnes et un point dans les nombres : tu lui précises les deux.
import pandas as pd
df = pd.read_csv("releves.csv", sep=";", decimal=",")
sep donne le séparateur, decimal le signe des décimales (documentation de read_csv). Un coup d'œil au fichier avant de le charger te dit quoi écrire.
Piège classique : oublier decimal=",". Le chargement passe sans message, mais « 19,5 » est lu comme du texte : la colonne temperature devient une colonne de chaînes de caractères, et une moyenne de texte n'a pas de sens. Le symptôme se voit dans df.info().
Vérifier ce que pandas a compris
Avant tout calcul, trois instructions te disent si le fichier a été bien lu.
print(df.shape)
print(df.head())
df.info()
df.shape donne le nombre de lignes et de colonnes, ligne des titres non comptée : ici (8, 3). Si tu ne vois qu'une colonne, dont le nom contient des points-virgules, le séparateur n'est pas le bon.
df.head() affiche les cinq premières lignes. Compare-les au fichier : les virgules des nombres sont devenues des points, et la case vide du mardi de B204 s'affiche NaN (not a number), la marque d'une valeur manquante.
df.info() donne, pour chaque colonne, le nombre de valeurs présentes et le type de données (le dtype). Pour temperature, tu dois lire 7 non-null et float64 : sept valeurs sur huit, des nombres à virgule. salle et jour sont du texte, affiché str depuis pandas 3.0 et object avant. Une colonne de nombres affichée en texte cache un intrus : une virgule décimale, une unité collée (« 19,5 °C ») ou un mot comme « panne ». Enfin, info() affiche son résumé elle-même : un print autour ajouterait un None inutile.
Répondre à une question avec groupby
Quelle salle est la plus chaude en moyenne ? groupby répartit les lignes en groupes qui partagent la même valeur dans une colonne, puis fait le calcul dans chaque groupe.
groupes = df.groupby("salle")["temperature"]
print(groupes.mean())
print(groupes.size())
print(groupes.count())
Vérifie toujours un groupe à la main. Pour A101 :
$$\frac{19{,}5 + 20{,}1 + 19{,}8}{3} = \frac{59{,}4}{3} = 19{,}8$$
Pour B204, pandas calcule $\dfrac{22{,}4 + 21{,}8}{2} = 22{,}1$ : mean() laisse de côté la case vide du mardi.
| Salle | size() | count() | mean() en °C |
|---|---|---|---|
| A101 | 3 | 3 | 19,8 |
| B204 | 3 | 2 | 22,1 |
| C010 | 2 | 2 | 18,1 |
Réponse : B204. Pour ne garder que certaines lignes, écris une condition entre crochets : df[df["salle"] == "B204"] renvoie les trois relevés de B204.
Piège classique : size() compte les lignes du groupe, count() seulement les valeurs présentes. B204 a 3 lignes mais 2 températures : sa moyenne repose sur deux mesures. Avant d'annoncer un résultat, regarde sur combien de valeurs il s'appuie.
Une case vide, une décision à prendre
Ce NaN n'est pas un zéro : le capteur de B204 n'a rien transmis le mardi, et personne ne sait quelle température il faisait. Que faire de cette case, c'est à toi de le décider, pas à pandas.
La laisser vide est souvent le plus honnête : les calculs l'ignorent, et tu précises que B204 n'a que deux mesures. Si la suite exige un tableau complet, df = df.dropna(subset=["temperature"]) retire les lignes sans température. La remplacer demande une valeur justifiée, celle d'un thermomètre de secours par exemple, signalée dans ton compte rendu. Un zéro serait une fausse mesure : l'exercice 3 montre ce qu'il fait au classement.
Piège classique : des exemples écrits avant pandas 3.0 remplacent les cases vides avec df["temperature"].fillna(21.5, inplace=True). Depuis pandas 3.0, cette ligne ne modifie plus df : la colonne sélectionnée se comporte comme une copie, et seule la copie change (guide Copy-on-Write). Écris une affectation, avec le signe =, qui marche dans toutes les versions : df["temperature"] = df["temperature"].fillna(21.5).
Exercices corrigés
Les trois premiers reprennent les relevés. Cherche sur ta feuille avant d'ouvrir la correction.
Exercice 1 : df["temperature"].describe() affiche entre autres count, mean, min, 50% et max. Calcule ces cinq valeurs à la main, la moyenne au centième près.
Correction :
La case vide n'est pas comptée : count vaut 7.
La somme des sept valeurs vaut $19{,}5 + 20{,}1 + 19{,}8 + 22{,}4 + 21{,}8 + 17{,}8 + 18{,}4 = 139{,}8$, donc la moyenne vaut $\dfrac{139{,}8}{7} \approx 19{,}97$ °C.
Rangées dans l'ordre : 17,8 ; 18,4 ; 19,5 ; 19,8 ; 20,1 ; 21,8 ; 22,4. Donc min vaut 17,8 °C, max 22,4 °C, et la médiane 50% est la quatrième valeur sur sept : 19,8 °C.
Les lignes 25% et 75% (18,95 et 20,95) sont calculées entre deux valeurs voisines : elles peuvent différer des quartiles de ta calculatrice.
Exercice 2 : On exécute chauds = df[df["temperature"] > 21] puis frais = df[df["temperature"] <= 21]. Combien de lignes contient chacun ? Un camarade attend un total de 8 : a-t-il raison ?
Correction :
Au-dessus de 21 °C, il y a 22,4 et 21,8, les relevés de B204 du lundi et du mercredi : chauds a 2 lignes.
À 21 °C ou moins, il y a 19,5 ; 20,1 ; 19,8 ; 17,8 et 18,4 : frais a 5 lignes.
Total : 7, pas 8. Comparer une valeur manquante avec > ou <= donne faux, donc le mardi de B204 n'entre dans aucun des deux filtres. Une condition et son contraire ne couvrent pas tout le tableau dès qu'il y a des cases vides.
Exercice 3 : Pour « boucher le trou », un camarade écrit df["temperature"] = df["temperature"].fillna(0), puis recalcule la moyenne par salle. Que trouve-t-il pour B204, et quel classement des salles, de la plus chaude à la plus froide ? Que lui conseilles-tu ?
Correction :
Après cette ligne, le mardi de B204 vaut 0 et compte comme une mesure : $\dfrac{22{,}4 + 0 + 21{,}8}{3} = \dfrac{44{,}2}{3} \approx 14{,}73$ °C.
A101 et C010 ne changent pas (19,8 et 18,1 °C). Le classement devient A101, C010, B204 : la salle aux deux relevés les plus élevés passe pour la plus froide.
Conseil : laisser la case vide, ce qui redonne 22,1 °C, ou retirer la ligne avec dropna, puis préciser que B204 n'a que deux relevés.
Exercice 4 : Une association étudiante a noté la durée du trajet domicile-campus de six adhérents, en minutes, dans trajets.csv (données fictives) :
etudiant;mode;duree
Ines;velo;18
Hugo;bus;35
Lea;bus;41
Sami;velo;22
Noe;voiture;
Jade;bus;29
a) Écris l'instruction de chargement. b) Que donnent df.shape et, pour duree, df.info() ? c) Calcule df.groupby("mode")["duree"].mean() et dis quel mode est le plus rapide.
Correction :
a) Séparateur point-virgule, aucune décimale : df = pd.read_csv("trajets.csv", sep=";").
b) df.shape vaut (6, 3). Pour duree, df.info() affiche 5 non-null et float64, pas int64 : une colonne d'entiers qui contient une case vide passe en nombres à virgule, parce que NaN est lui-même un nombre à virgule.
c) Bus : $\dfrac{35 + 41 + 29}{3} = \dfrac{105}{3} = 35$ min. Vélo : $\dfrac{18 + 22}{2} = 20$ min. Voiture : aucune valeur, la moyenne vaut NaN. Le vélo est le plus rapide, avec 20 min en moyenne, mais sur deux trajets seulement : c'est une observation, pas une conclusion.
À retenir
À retenir :
- Un CSV à la française se charge avec
sep=";"etdecimal=",". - Juste après le chargement :
shape,head()etinfo(). Une colonne de nombres lue comme du texte trahit une erreur de lecture. groupbydonne un résultat par groupe : vérifies-en un à la main.size()compte les lignes,count()les valeurs présentes, etmean()ignore les cases vides.- Une case vide n'est pas un zéro, et elle sort des filtres en
>comme en<=. - Pour modifier une colonne, une affectation
df["col"] = ..., jamaisinplace=Truesur une colonne sélectionnée.
Sources
- Documentation de pandas, fonction
read_csv: pandas.pydata.org. - Documentation de pandas, guide Copy-on-Write, seul mode de fonctionnement depuis pandas 3.0 : pandas.pydata.org.
- Notes de la version 3.0.0 de pandas, publiée le 21 janvier 2026, avec le type
strpar défaut pour le texte : pandas.pydata.org.