HOWTO · Pandas

依欄值篩選 pandas DataFrame 資料列

使用布林遮罩、loc、isin、between、文字與遺漏值檢查或 query,依欄值篩選 pandas DataFrame 資料列。

本頁內容

篩選資料列就是為每列產生一個布林值,並保留值為 True 的資料列。通用寫法是 df.loc[條件];第二個參數也能同時指定輸出欄。

建立範例 DataFrame

範例表包含文字、數值、日期及遺漏的產品名稱。後續範例都重複使用 orders。篩選會保留原索引;只有確實需要新索引時才呼叫 .reset_index(drop=True)

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

依單一欄值篩選資料列

將 Series 與目標值比較即可建立遮罩。一般方括號會選出相同資料列,但 .loc 還能明確選欄。以 != 排除精確值,並以 isna()notna() 處理遺漏值。

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

輸出:

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

輸出:

 order_id  sales
      101    450
      104    700
      106    410

組合多個條件

使用 &|~ 進行逐元素的且、或、非運算,並以括號包住每個比較。Python 的 andor 只接受單一真值,對 Series 使用會產生真值不明確的錯誤。

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

輸出:

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

依值清單篩選

Series.isin() 可取代冗長的相等比較。參數必須是清單等類清單集合,不能是單獨字串。排除值時,應對 isin() 的完整結果套用 ~

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

輸出:

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

篩選數值範圍與日期

between() 預設包含兩端,也適用於經 pd.to_datetime() 轉換的日期。若資料帶有時區,邊界值必須使用相容時區。

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

輸出:

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

篩選遺漏值或非遺漏值

isna() 會找出 NoneNaNNaTnotna() 則要求值存在。空字串不會自動視為遺漏值,必須另外正規化或判斷。

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

輸出:

 order_id product
      105    None

篩選文字值

str.contains() 會建立向量化字串遮罩。regex=False 按照字面文字搜尋,case=False 忽略大小寫,na=False 明確把遺漏文字視為不相符。

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

輸出:

 order_id   product
      101      Desk
      103 Desk lamp
      104      Desk

使用 DataFrame.query() 撰寫易讀運算式

query() 中,@ 參照區域變數,含空格的欄名以反引號包住。不要將不可信輸入串接至運算式,因為求值時可能執行程式碼。

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

輸出:

 order_id region  sales
      101   East    450
      106   East    410

選擇 .loc、方括號或 query()

一般優先使用 .loc,僅篩選資料列的簡短寫法可用方括號;受控運算式確實較易讀時再用 query()。修改獨立結果前使用 .copy()

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

避免索引對齊與資料型別問題

遮罩會依索引標籤對齊,因此應由同一 DataFrame 建立。比較前先轉換數值文字與日期;只有規則需要時才正規化大小寫或空白。

重複使用並偵錯布林遮罩

具名遮罩便於檢查、計數及測試。沒有相符項目時會回傳有效的空 DataFrame。DataFrame.filter() 篩選軸標籤,而非依儲存格值篩選資料列。

篩選時不變更來源資料

若要修改原表,應透過原 DataFrame 的 .loc 指派;若要建立獨立工作集,則使用複本。如此不會依賴鏈式索引或不確定的記憶體共享。

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