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