HOWTO · Pandas

Filtrare le righe di un DataFrame pandas in base ai valori delle colonne

Filtra le righe di un DataFrame pandas con maschere booleane, loc, isin, between, test di testo e valori mancanti o query.

In questa pagina

Filtrare significa creare un booleano per ogni riga e mantenere quelle con valore True. La forma generale df.loc[condizione] è chiara; il secondo argomento seleziona anche le colonne di output.

Creare il DataFrame di esempio

La tabella contiene testo, numeri, date e un prodotto mancante. Gli esempi successivi riutilizzano orders. L’indice originale rimane; reimpostalo solo se serve davvero un nuovo indice.

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"]),
    }
)

Filtrare le righe per un valore di colonna

Il confronto di una Series crea la maschera. Le parentesi quadre semplici selezionano le stesse righe, ma .loc può scegliere anche le colonne. Usa != per escludere e isna() o notna() per i mancanti.

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

Output:

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

Output:

 order_id  sales
      101    450
      104    700
      106    410

Combinare più condizioni

Combina condizioni elemento per elemento con &, | e ~, racchiudendo ogni confronto tra parentesi. Gli operatori Python and e or richiedono un solo booleano e causano l’errore di verità ambigua con una Series.

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

Output:

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

Filtrare per un elenco di valori

Series.isin() sostituisce lunghe catene di confronti. Passa una lista o una raccolta simile, non una singola stringa. Per escludere valori, applica ~ all’intero risultato di isin().

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

Output:

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

Filtrare intervalli e date

between() include entrambe le estremità per impostazione predefinita e funziona anche con date convertite con pd.to_datetime(). I limiti devono avere una zona oraria compatibile.

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

Output:

 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"]]

Filtrare valori mancanti o presenti

isna() seleziona None, NaN e NaT; notna() richiede un valore presente. Una stringa vuota non è automaticamente mancante e va gestita separatamente.

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

Output:

 order_id product
      105    None

Filtrare valori testuali

str.contains() crea una maschera vettoriale. regex=False cerca testo letterale, case=False ignora maiuscole e minuscole e na=False esclude esplicitamente i testi mancanti.

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

Output:

 order_id   product
      101      Desk
      103 Desk lamp
      104      Desk

Usare DataFrame.query() per espressioni leggibili

In query(), @ indica una variabile locale e i nomi di colonna con spazi richiedono backtick. Non concatenare input non attendibile: l’espressione viene valutata e può eseguire codice.

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

Output:

 order_id region  sales
      101   East    450
      106   East    410

Scegliere tra .loc, parentesi quadre e query()

Usa .loc come scelta generale, le parentesi quadre per la sola selezione di righe e query() per espressioni controllate più leggibili. Usa .copy() prima di modificare un risultato indipendente.

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

Evitare sorprese di allineamento e tipo

Le maschere si allineano per indice, quindi creale dallo stesso DataFrame. Converti testo numerico e date prima del confronto; normalizza testo solo quando la regola lo richiede.

Riutilizzare e controllare le maschere booleane

Una maschera con nome si può contare, ispezionare e testare. Nessuna corrispondenza restituisce un DataFrame vuoto valido. DataFrame.filter() seleziona etichette dell’asse, non righe per valore.

Filtrare senza modificare i dati sorgente

Per modificare l’originale assegna tramite .loc; per un nuovo dataset crea una copia. La scelta esplicita evita di dipendere dall’indicizzazione concatenata o dalla memoria condivisa.

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