布尔索引df[condition]是最直接的行筛选方式,需用外层方括号;注意空值处理、大小写敏感性、多条件括号、str.contains()替代==、isin()替代冗长|判断、query()适用于复杂可读场景但有性能与语法限制。

用 df[condition] 做布尔索引是最直接的方式
Pandas 里筛选含特定值的行,核心就是构造一个布尔序列,然后用它去索引 DataFrame。不是用 query(),也不是先 iterrows() 再判断——那太慢还容易出错。
常见错误是写成 df['col'] == 'value' 后忘了套进方括号,结果返回的是 Series 而不是过滤后的 DataFrame。
- 必须写成
df[df['col'] == 'value'],外层方括号才是筛选动作 - 字符串比较注意大小写:
df['name'].str.lower() == 'alice'比直接== 'Alice'更稳妥 - 空值(
NaN)会让布尔表达式变成False,但不会报错;如果想包含空值,得显式加| df['col'].isna() - 多个条件用括号包住每个子表达式:
df[(df['age'] > 25) & (df['city'] == 'Beijing')],别漏括号,也别用and
查“包含子串”别用 ==,要用 str.contains()
想筛出“姓名里有‘明’字”的行,df['name'] == '明' 是错的——那是找完全等于“明”的整字段。真实场景大多是模糊匹配。
str.contains() 默认区分大小写、不支持正则(除非关掉 regex=False),但够用且不易出错。
- 基础用法:
df[df['name'].str.contains('明')] - 忽略大小写:
df[df['name'].str.contains('abc', case=False)] - 匹配整个单词(避免匹配到“abcde”里的“abc”):
df[df['text'].str.contains(r'\babc\b', regex=True)] - 空值默认返回
NaN,导致该行被丢弃;加na=False可让空值算作False:.str.contains('x', na=False)
isin() 查多个候选值比连写 | 更快更安全
要找城市是“北京”、“上海”或“广州”的行,有人会写 (df['city'] == '北京') | (df['city'] == '上海') | ...。这不仅啰嗦,而且一旦候选值多、类型杂(比如混了 None 或数字),很容易漏判或报错。
isin() 是专为此设计的,内部做了优化,还能自动处理 NaN 和类型兼容性问题。
- 正确写法:
df[df['city'].isin(['北京', '上海', '广州'])] - 支持列表、元组、集合、甚至另一个 Series 的值:
df[df['id'].isin(other_df['id'])] - 注意:如果右边列表里有
NaN,isin()会把它当普通值处理(即匹配NaN行),但多数时候你并不想要这个效果——提前用dropna()过滤更可控 - 性能上,10 万行数据里查 100 个值,
isin()比等价的布尔表达式快 3–5 倍
用 query() 写复杂条件更易读,但要注意变量引用和性能
当条件嵌套深、涉及多个列运算(比如 price * qty > 1000),或者想把变量名直接塞进字符串里,query() 就比链式布尔索引顺手。
但它不是万能的:语法是字符串,IDE 不提示、运行时报错才暴露;而且底层要解析字符串,小数据看不出差别,大数据量下比原生布尔索引慢 10%–20%。
- 引用外部变量加
@:df.query('age > @min_age and city in @cities'),其中min_age=25、cities=['Beijing'] - 列名含空格或特殊字符,得用反引号:
df.query('`user id` == 123') - 不能在
query()里调用方法,比如.str.contains()不支持;这种只能回退到布尔索引 - 调试时如果报
UndefinedVariableError,八成是变量没加@,或者作用域不对(比如在函数内调用但变量是局部的)
真正卡住人的往往不是语法,而是空值怎么算、大小写要不要管、正则边界符写没写、还有那个总被漏掉的外层方括号——这些地方一错,结果就静默变少几行,很难察觉。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











