query函数多条件需用括号包裹每个比较式并用&/|连接,列名含空格或特殊字符时须加反引号,字符串方法需指定engine='python',数值比较无需指定引擎。

query函数里怎么写多条件,才不会报错
直接写 df.query('Age > 18 and Name.str.startswith("A")') 大概率能跑通,但前提是列名不含空格、点号或特殊字符。一旦列名是 'user id' 或 'price (USD)',就得用反引号包裹:df.query('`user id` > 100 and `price (USD)` > 50')。不加反引号会触发 UndefinedVariableError 或语法解析失败。
字符串方法调用(如 .str.contains())必须显式启用 Python 引擎:engine='python',否则默认的 numexpr 引擎不支持;数值比较、布尔运算这类基础操作则无需指定引擎。
常见错误现象:
-
KeyError: 'Name':列名大小写或拼写不一致,或 DataFrame 列名含不可见空格 -
TypeError: unsupported operand type(s) for &: 'str' and 'bool':误把&当成字符串连接符用了,实际 query 里该用and/or -
ParserError:条件中混用了单双引号嵌套,比如'name == "Alice's",应改用三重引号或转义
布尔索引写多条件时,括号为什么不能省
因为 &、|、~ 是位运算符,优先级高于比较运算符 ==、>。写成 df['A'] == 1 & df['B'] == 2,Python 实际按 df['A'] == (1 & df['B']) == 2 解析,立刻报 ValueError: The truth value of a Series is ambiguous。
立即学习“Python免费学习笔记(深入)”;
必须给每个比较条件加括号:(df['A'] == 1) & (df['B'] == 2)。这是硬性语法要求,不是风格建议。
容易踩的坑:
- 用
and/or替代&/|:会触发真值测试错误,因为 pandas 不允许对整个 Series 调用bool() - 漏掉最外层括号:比如
df[(df['A'] == 1) & df['B'] == 2],&右侧没括号,依然报错 - 混合使用
&和and:逻辑混乱,且必然报错
isin() 配合其他条件时,数据类型不一致怎么办
df['Year'].isin([2022, 2023]) 和 df['Year'] == '2022' 看似都“在筛年份”,但若 df['Year'].dtype 是 int64,后者永远返回全 False —— 字符串和整数比较结果为 False,不是类型错误,所以不报异常,只默默返回空结果。
正确做法是先确认类型:print(df['Year'].dtype) 和 df['Year'].head().tolist(),再决定写法:
- 整数型 → 用数字:
df[df['Item Code'].isin(['04901','04940']) & (df['Year'] == 2022)] - 字符串型 → 用字符串:
df[df['Item Code'].isin(['04901','04940']) & (df['Year'] == '2022')] - 不确定 → 统一转类型:
df['Year'].astype(str).isin(['2022', '2023'])或pd.to_numeric(df['Year'], errors='coerce').isin([2022, 2023])
注意:isin() 对 NaN 默认返回 False;如果想保留缺失值行,得额外加 | df['col'].isna()。
query 和布尔索引性能差异在哪
简单条件(如 col > 100)下,两者性能几乎无差别;但涉及字符串方法(.str.contains)、复杂表达式或大内存 DataFrame 时,query() 通常更快,因为它底层用 numexpr 做向量化计算,避免 Python 解释器开销。
不过 query() 有硬限制:不支持自定义函数、不能访问外部变量(除非用 @var 注入),也不支持链式赋值(df.query(...).loc[:, 'new_col'] = ... 容易触发 SettingWithCopyWarning)。
实操建议:
- 快速探索、交互分析 → 优先用
query(),可读性强 - 需复用中间布尔数组(比如先筛再统计再画图)→ 用布尔索引,显式存为
mask = (df.A > 1) & (df.B - 条件含
np.where、pd.cut或自定义逻辑 → 只能用布尔索引
最常被忽略的一点:无论用哪种方式,筛选结果都是新对象,修改它不会影响原 df;若需就地更新,必须明确用 .loc 或 .iloc 定位赋值。


















