pandas
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)