DataFrame 查询
在 Pandas 中,筛选条件本质上是一个与索引对齐的布尔 Series。
import pandas as pd
orders = pd.DataFrame({
"customer_id": ["C1", "C2", None],
"amount": [120, 80, 200],
"status": ["paid", "shipped", "pending"],
"created_at": pd.to_datetime(["2026-01-02", "2026-03-31 12:00", "2026-04-01"], format="mixed"),
})
mask = orders["amount"].ge(100) & orders["status"].isin(["paid", "shipped"])
large_orders = orders.loc[mask, ["customer_id", "amount", "status"]]
谓词编写规范
- 括号是必须的:使用
&、|或~组合多个条件时,务必给每个比较表达式加上括号,因为运算符优先级容易出错。 - 专用方法:成员判断用
isin,闭区间范围用between,缺失值检测用isna/notna。 - 类型访问器:针对字符串、日期时间和分类数据,分别使用
.str、.dt和.cat访问器进行类型化操作。 - 索引对齐陷阱:如果掩码(mask)是从其他对象构建的,务必检查其索引。索引对齐机制可能会意外改变最终选中的行。
recent = orders.loc[
orders["created_at"].ge("2026-01-01") & orders["created_at"].lt("2026-04-01")
]
missing_customer = orders.loc[orders["customer_id"].isna()]
query 方法
DataFrame.query 能让复杂的分析表达式更易读:
threshold = 100
result = orders.query("amount >= @threshold and status == 'paid'")
何时不用 query?
- 列名包含特殊字符或难以阅读时。
- 谓词需要动态构建时。
- 你更倾向于使用标准 Python 调试工具时。
安全警告:切勿将来自不可信输入的字符串直接拼接进 query 中,它不是安全边界,存在注入风险。
筛选(Filter)与选择(Select)
- 筛选:通过谓词选择行。
.loc:可以同时指定行和列(基于标签)。.iloc:基于位置索引选择行和列。
保持“筛选”和“选择”这两个概念在逻辑上的分离,能有效避免许多因形状(shape)或标签(label)不匹配导致的错误。
核对选中的行
这里 large_orders 的形状为 (1, 3),保留第 0 行;result 也保留第 0 行,但保留全部四列。recent 保留第 0、1 行。日期采用左闭右开区间,因此包含 3 月 31 日全天;上界若写成 "2026-03-31",实际上是当天零点,会漏掉下午的记录。
布尔索引把可空布尔掩码中的缺失项视为假。只有需要保留判断结果未知的行时,才使用 mask.fillna(True)。Python 的 and/or 不能逐元素组合 Series,应使用 &/|。DataFrame.filter 虽然叫 filter,却按轴标签筛选,不按单元格值筛选行。query 能执行任意代码,不能接收不可信表达式。