pandas : manipuler des tableaux de données en Python

pandas apporte à Python le DataFrame, un tableau à colonnes nommées qui remplace les boucles écrites à la main sur des fichiers de données.
5 min de lecture
Believemy logo

Définition

Traiter un fichier de données avec les seuls outils du langage tient du bricolage : une boucle pour lire les lignes, un dictionnaire pour cumuler les totaux. pandas évite ce bricolage : il ajoute à Python un objet qu'il n'a pas en standard, le DataFrame, un tableau à colonnes nommées, chacune portant son propre type. Là où une liste de dictionnaires oblige à parcourir les lignes une par une, un DataFrame se manipule colonne par colonne, en une seule expression.

Ce que ça donne concrètement, sur un fichier de ventes :

PYTHON
import pandas as pd

ventes = pd.read_csv("ventes.csv")
print(ventes["montant"].sum())
print(ventes[ventes["pays"] == "France"].head())

Il ne fait pas partie de la bibliothèque standard : il s'installe avec pip, de préférence dans un environnement virtuel, faute de quoi le premier import lève une ModuleNotFoundError.

BASH
pip install pandas

Les données viennent rarement d'un seul fichier CSV. pandas lit aussi les feuilles Excel, le JSON et le résultat d'une requête SQL, et ce qui en sort se trace ensuite avec matplotlib sans conversion intermédiaire.


Le problème concret qu'il résout

Le vrai concurrent de pandas n'est pas une autre bibliothèque, c'est la boucle écrite à la main. Calculer un chiffre d'affaires par pays sans lui demande un dictionnaire d'accumulation, une itération, un traitement à part des lignes incomplètes et un tri final, et rien de tout cela ne reste lisible six mois plus tard. Avec pandas, la même chose tient sur une ligne, en un coup d'œil.

La comparaison se voit mieux côte à côte :

PYTHON
# Sans pandas
totaux = {}
for ligne in lignes:
    totaux[ligne["pays"]] = totaux.get(ligne["pays"], 0) + ligne["montant"]

# Avec pandas
totaux = ventes.groupby("pays")["montant"].sum()

Le gain se paie. Le fichier est chargé entièrement en mémoire, l'importation coûte environ une seconde au démarrage, et la syntaxe s'apprend comme un second langage. Sur cinquante lignes traitées une seule fois, une compréhension de liste et le module csv font le travail plus vite, sans dépendance à installer.

Le choix se résume presque toujours à la taille et à l'usage du tableau :

SituationL'outil adapté
Quelques centaines de lignes, un seul calculLe module csv et une boucle
Tableau à explorer, croiser, agrégerpandas
Matrices de nombres, calcul numérique purnumpy
Volume qui dépasse la mémoire disponibleUne base de données, ou un outil qui travaille sur disque


L'erreur classique de ceux qui débutent

La faute la plus commune, chez qui débute, consiste à traiter le DataFrame comme une liste et à boucler dessus avec iterrows. Le code donne le bon résultat, ce qui le rend difficile à suspecter, mais il est des dizaines de fois plus lent que l'écriture attendue, car chaque tour reconstruit un objet Python là où pandas sait opérer sur la colonne entière d'un seul coup.

La différence se voit en réécrivant le même calcul des deux façons :

PYTHON
# Lent, et ce n'est pas la faute de la machine
for i, ligne in ventes.iterrows():
    ventes.at[i, "ttc"] = ligne["montant"] * 1.2

# Attendu
ventes["ttc"] = ventes["montant"] * 1.2
Attention

Sur quelques centaines de lignes, la différence ne se sent pas. Sur plusieurs centaines de milliers de lignes, elle sépare un script qui répond en une seconde d'un autre encore en cours une minute plus tard, pour le même résultat.

La deuxième erreur consiste à modifier un extrait en croyant modifier l'original. ventes[ventes["montant"] > 100]["remise"] = 5 écrit dans une copie temporaire et ne change rien au tableau de départ. La forme correcte désigne les lignes et la colonne en une seule opération : ventes.loc[ventes["montant"] > 100, "remise"] = 5. Un nom de colonne mal orthographié, lui, lève une KeyError, exactement comme sur un dictionnaire.


Les valeurs manquantes ne sont pas None

Un fichier de données réel a presque toujours des trous : un âge non renseigné, une mesure qu'un capteur n'a pas su prendre. Python répond d'ordinaire à une absence de valeur par None, mais pandas fait un autre choix : une case vide devient NaN, qui est un float d'un genre particulier. La conséquence surprend : une colonne d'entiers contenant un seul trou bascule entièrement en nombres à virgule, et NaN == NaN répond faux, ce qui rend tout test d'égalité inutilisable pour les repérer.

Bon à savoir

NaN signifie « Not a Number », une valeur de la norme IEEE 754, qui régit le calcul en virgule flottante sur la quasi-totalité des ordinateurs, bien avant Python ou pandas.

Trois méthodes remplacent ce test défaillant :

PYTHON
ventes["remise"].isna().sum()      # Combien de trous
ventes["remise"].fillna(0)         # Les remplacer
ventes.dropna(subset=["montant"])  # Ou retirer ces lignes

Choisir entre remplir et retirer n'est pas une question technique. Remplacer une remise absente par zéro est juste ; remplacer une température absente par zéro fausse la moyenne de toute la série. C'est exactement le genre d'arbitrage qu'un tableur laisse invisible et qu'une ligne de code rend explicite et relisible.


Questions fréquentes

Question

Faut-il apprendre numpy avant pandas ?

Non. La bibliothèque repose dessus, mais ne l'exige pas de son utilisateur : on charge, filtre et agrège un fichier sans jamais écrire une ligne de numpy. Le détour devient utile le jour où il faut du calcul matriciel, ou une performance que le travail par colonnes ne suffit plus à donner.

Question

Remplace-t-il Excel ou une base de données ?

Ni l'un ni l'autre. Il remplace le geste manuel dans Excel, pas Excel lui-même : un traitement écrit se rejoue à l'identique le mois suivant, sans refaire les mêmes clics. Face à une base de données, il ne remplace rien : il consomme le résultat d'une requête et laisse le stockage au serveur.

Question

Mon fichier ne tient pas en mémoire, que faire ?

Un tableau en mémoire occupe souvent plusieurs fois la taille du fichier d'origine. Trois réflexes règlent la majorité des cas : ne lire que les colonnes utiles avec usecols, imposer les types avec dtype, et traiter le fichier par morceaux avec chunksize. Au-delà, le problème n'est plus de bibliothèque mais de stockage.

Termes connexes

Découvrez notre glossaire Python

Parcourez les termes et définitions les plus couramment utilisés dans le domaine du développement avec Python.

Partager cet article

Tu veux nous aider ? Fais un lien vers cet article sur tes réseaux ou encore mieux : sur ton site, dans un article ou dans ta newsletter.