~/wiki

pandas

Mis à jour le 2026-08-07Confiance : high
pandaspythondataframedatacsvanalyse

Charger et regarder

import pandas as pd

df = pd.read_csv("ventes.csv")
df = pd.read_csv("ventes.csv", sep=";", parse_dates=["date"], dtype={"code": str})
df = pd.read_parquet("ventes.parquet")
df = pd.read_json("ventes.json")
df.head(3)
df.info()
df.describe()
df.shape
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1240 entries, 0 to 1239
Data columns (total 4 columns):
 #   Column   Non-Null Count  Dtype
---  ------   --------------  -----
 0   date     1240 non-null   datetime64[ns]
 1   produit  1240 non-null   object
 2   region   1198 non-null   object
 3   montant  1240 non-null   float64

info() est le premier réflexe : il donne d'un coup les types et les valeurs manquantes. dtype: object sur une colonne censée être numérique signale presque toujours un problème de parsing.

Sélectionner

df["montant"]                 # une Series
df"produit", "montant"    # un DataFrame
df.loc[3, "montant"]          # par label
df.iloc[3, 2]                 # par position
df.loc[df["montant"] > 100, ["produit", "montant"]]

Filtres combinés : parenthèses obligatoires, et & | ~ au lieu de and or not.

df[(df["montant"] > 100) & (df["region"] == "IDF")]
df[df["produit"].isin(["A", "B"])]
df[df["produit"].str.contains("chaise", case=False, na=False)]
df.query("montant > 100 and region == 'IDF'")

Valeurs manquantes

df.isna().sum()
df.dropna(subset=["region"])
df["region"] = df["region"].fillna("inconnue")
df.isna().sum()
date        0
produit     0
region     42
montant     0
dtype: int64

Grouper et agréger

df.groupby("region")["montant"].sum()
df.groupby("region")["montant"].agg(["sum", "mean", "count"])
df.groupby(["region", "produit"], as_index=False).agg(
    total=("montant", "sum"),
    n=("montant", "size"),
)
df.groupby("region")["montant"].agg(["sum", "mean", "count"])
              sum    mean  count
region
IDF      184203.5  312.55    589
PACA      92310.0  287.29    321
Bretagne  61044.2  254.35    240

as_index=False évite d'avoir à faire .reset_index() juste après.

Transformer

df["ttc"] = df["montant"] * 1.2
df["mois"] = df["date"].dt.to_period("M")
df["cat"] = df["montant"].apply(lambda x: "gros" if x > 500 else "petit")

df = df.rename(columns={"montant": "ht"})
df = df.drop(columns=["temp"])
df = df.sort_values("ht", ascending=False)
df = df.astype({"code": "string", "n": "int32"})

apply sur une Series est lent. Préférer les opérations vectorisées, ou np.where / pd.cut pour les cas conditionnels :

import numpy as np
df["cat"] = np.where(df["ht"] > 500, "gros", "petit")

Joindre et empiler

pd.merge(cmd, clients, on="client_id", how="left")
pd.merge(a, b, left_on="id", right_on="ref", how="inner")
pd.concat([df_jan, df_fev], ignore_index=True)     # empile verticalement

how : left, right, inner, outer. Après un merge, vérifier len(df) — une explosion du nombre de lignes révèle une clé non unique.

Pivots

df.pivot_table(index="region", columns="mois", values="ht", aggfunc="sum", fill_value=0)
df.melt(id_vars=["region"], var_name="mois", value_name="ht")   # l'inverse

Le SettingWithCopyWarning

sub = df[df["ht"] > 100]
sub["remise"] = 0.1          # ⚠️ warning : sub peut être une vue

Corriger avec une copie explicite :

sub = df[df["ht"] > 100].copy()
sub["remise"] = 0.1

Ou modifier en place sur l'original : df.loc[df["ht"] > 100, "remise"] = 0.1.

Exporter

df.to_csv("out.csv", index=False)
df.to_parquet("out.parquet")            # plus rapide et typé, à préférer
df.to_json("out.json", orient="records")

index=False presque toujours, sinon on récupère une colonne Unnamed: 0 au rechargement.

Options d'affichage

pd.set_option("display.max_columns", None)
pd.set_option("display.width", 200)
pd.set_option("display.float_format", "{:.2f}".format)

See also