HOWTO · Pandas

Filtrer les lignes d’un DataFrame pandas selon les valeurs d’une colonne

Filtrez les lignes d’un DataFrame pandas avec des masques booléens, loc, isin, between, des tests de texte ou query.

Sur cette page

Filtrer revient à produire un booléen par ligne et à conserver celles dont la valeur est True. La forme générale df.loc[condition] est claire ; son second argument sélectionne également les colonnes de sortie.

Créer le DataFrame d’exemple

La table contient du texte, des nombres, des dates et une valeur manquante. Les exemples suivants réutilisent orders. L’index d’origine est conservé ; ne le réinitialisez que si le résultat l’exige.

import pandas as pd

orders = pd.DataFrame(
    {
        "order_id": [101, 102, 103, 104, 105, 106],
        "region": ["East", "West", "East", "North", "West", "East"],
        "product": ["Desk", "Chair", "Desk lamp", "Desk", None, "Chair"],
        "sales": [450, 275, 125, 700, 320, 410],
        "status": ["paid", "pending", "paid", "paid", "cancelled", "pending"],
        "ordered_at": pd.to_datetime(["2026-08-01", "2026-08-03", "2026-08-08", "2026-08-11", "2026-08-14", "2026-08-18"]),
    }
)

Filtrer les lignes selon une valeur de colonne

La comparaison d’une Series crée le masque. Les crochets simples donnent les mêmes lignes, mais .loc sélectionne aussi les colonnes. Utilisez != pour exclure une valeur et isna() ou notna() pour les valeurs manquantes.

east_orders = orders.loc[orders["region"] == "East"]
print(east_orders[["order_id", "region", "sales"]].to_string(index=False))

Sortie :

 order_id region  sales
      101   East    450
      103   East    125
      106   East    410
large_orders = orders.loc[orders["sales"] >= 400, ["order_id", "sales"]]
print(large_orders.to_string(index=False))

Sortie :

 order_id  sales
      101    450
      104    700
      106    410

Combiner plusieurs conditions

Combinez les conditions élément par élément avec &, | et ~, chaque comparaison étant entre parenthèses. Les opérateurs Python and et or attendent un seul booléen et déclenchent l’erreur de vérité ambiguë avec une Series.

mask = (orders["region"] == "East") & (orders["sales"] >= 400)
result = orders.loc[mask, ["order_id", "region", "sales"]]
print(result.to_string(index=False))

Sortie :

 order_id region  sales
      101   East    450
      106   East    410
mask = (orders["status"] == "paid") | (orders["sales"] > 600)
result = orders.loc[mask, ["order_id", "status", "sales"]]
# Raises ValueError: The truth value of a Series is ambiguous.
orders.loc[(orders["region"] == "East") and (orders["sales"] >= 400)]

Filtrer selon une liste de valeurs

Series.isin() remplace une longue suite de comparaisons. Passez une liste ou une collection similaire, jamais une chaîne seule. Pour exclure des valeurs, niez le résultat complet avec ~.

allowed = ["East", "West"]
result = orders.loc[orders["region"].isin(allowed), ["order_id", "region"]]
print(result.to_string(index=False))

Sortie :

 order_id region
      101   East
      102   West
      103   East
      105   West
      106   East
excluded = ["cancelled", "pending"]
paid_only = orders.loc[~orders["status"].isin(excluded)]

Filtrer des plages et des dates

between() inclut les deux bornes par défaut et accepte aussi les dates après conversion par pd.to_datetime(). Pour des données avec fuseau, les bornes doivent être compatibles.

mid_value = orders.loc[orders["sales"].between(300, 500), ["order_id", "sales"]]
print(mid_value.to_string(index=False))

Sortie :

 order_id  sales
      101    450
      105    320
      106    410
date_mask = orders["ordered_at"].between("2026-08-03", "2026-08-14")
result = orders.loc[date_mask, ["order_id", "ordered_at"]]

Filtrer les valeurs manquantes ou présentes

isna() repère None, NaN et NaT, tandis que notna() exige une valeur. Une chaîne vide n’est pas automatiquement manquante et doit être traitée séparément.

missing_product = orders.loc[orders["product"].isna(), ["order_id", "product"]]
present_product = orders.loc[orders["product"].notna()]
print(missing_product.to_string(index=False))

Sortie :

 order_id product
      105    None

Filtrer les valeurs textuelles

str.contains() crée un masque vectorisé. regex=False recherche un texte littéral, case=False ignore la casse et na=False classe explicitement les textes manquants comme non correspondants.

has_desk = orders["product"].str.contains("desk", case=False, regex=False, na=False)
result = orders.loc[has_desk, ["order_id", "product"]]
print(result.to_string(index=False))

Sortie :

 order_id   product
      101      Desk
      103 Desk lamp
      104      Desk

Utiliser DataFrame.query() pour des expressions lisibles

Dans query(), @ référence une variable locale et les colonnes contenant des espaces utilisent des accents graves. Ne concaténez jamais une entrée non fiable dans l’expression, car elle est évaluée et peut exécuter du code.

minimum_sales = 400
result = orders.query("region == 'East' and sales >= @minimum_sales")
print(result[["order_id", "region", "sales"]].to_string(index=False))

Sortie :

 order_id region  sales
      101   East    450
      106   East    410

Choisir entre .loc, les crochets et query()

Préférez .loc en général, les crochets pour une simple sélection de lignes et query() pour une expression contrôlée réellement plus lisible. Utilisez .copy() avant de modifier un résultat indépendant.

east_orders = orders.loc[orders["region"] == "East"].copy()
east_orders["sales_with_tax"] = east_orders["sales"] * 1.2

Éviter les surprises d’alignement et de type

Un masque est aligné sur les étiquettes d’index. Créez-le depuis le même DataFrame. Convertissez les textes numériques et les dates avant comparaison ; normalisez casse et espaces uniquement si la règle le demande.

Réutiliser et déboguer les masques booléens

Un masque nommé peut être inspecté, compté et testé. Aucun résultat produit un DataFrame vide valide. DataFrame.filter() sélectionne des étiquettes d’axe, et non des lignes selon les cellules.

Filtrer sans modifier les données sources

Pour modifier la source, affectez via .loc. Pour un nouveau jeu de travail, créez une copie. Ce choix explicite évite de dépendre de l’indexation chaînée ou d’un partage de mémoire incertain.

DataFrame.loc, Series.isin, Series.between, Series.str.contains, DataFrame.query