eval和query变快是因为绕过python解释器,交由pandas.eval内置的numexpr引擎(c+intel vml)处理;但仅当数据量大、无python函数、无自定义方法时生效。

eval 和 query 为什么能变快?不是因为“调用了 C”
它们快,是因为绕过了 Python 解释器对表达式树的逐层求值,直接把字符串交给 pandas.eval 内置的解析引擎(基于 numexpr)处理——后者在底层用 C 和 Intel VML 加速数组运算。但这个加速只在满足条件时才生效:数据量够大、表达式不含 Python 函数、不涉及自定义方法或闭包。
常见误判是以为写个 df.eval("a + b") 就自动飞起。实际上:
- 若 a 或 b 是 object 类型列,会退回到 Python 模式,比不用还慢
- 含 math.sin(x) 或 df.x.str.contains("abc") 这类调用,直接报 NotImplementedError
- 小于 10 万行的数据,eval 的编译开销可能反超纯 NumPy 运算
query 函数的三类典型提速场景
query 本质是带语法糖的 eval,专用于布尔筛选。它快的关键在于延迟执行和向量化过滤,但必须写对语法:
- 用
@引用外部变量:写df.query("x > @threshold"),别写df.query(f"x > {threshold}")(后者拼接字符串,失去优化) - 列名含空格或特殊字符,必须用反引号:
df.query("`user id` == 123") - 链式调用时注意作用域:
df.query("x > 0").query("y 比 <code>df.query("x > 0 and y 多一次拷贝,后者才是单次向量化过滤 - 避免在
query中调用方法:df.query("x.str.startswith('A')")会失败;得先用.str.startswith()算好布尔列再传入
eval 的安全边界和 dtype 隐患
eval 默认启用 engine="numexpr",但它不支持所有 NumPy 类型。最常踩的坑是:
-
datetime64[ns]列参与运算会触发 fallback 到 Python 模式,比如df.eval("date_col.dt.year > 2020")不被支持 -
category类型列若未预设顺序,eval可能静默转成object,后续比较出错 - 开启
parser="python"(如需用lambda)等于放弃全部加速,纯属自缚手脚 - 生产环境务必设
truediv=False避免除零异常中断(默认为True,会抛ZeroDivisionError)
实测建议:先用 df.dtypes 确认关键列是 float64/int64,再上 eval;否则宁可用 numpy.where 手写。
比 eval/query 更快的替代方案其实更常用
真要榨干 C 级性能,eval 和 query 只是“够用”的快捷键,不是终极解法:
- 简单二元运算(如
a + b * c):直接用 NumPy 数组操作,df["a"].values + df["b"].values * df["c"].values稳定最快 - 复杂条件过滤:用
numba.jit编译布尔函数,尤其当逻辑含循环或分支时,比query高出 3–5 倍 - 字符串批量处理:
df["col"].str底层已用 Cython,但若需正则提取,re.findall在map中仍是瓶颈,应换regex库 +Series.array直接喂给 C 层
真正卡住速度的,往往不是表达式解析,而是中间结果的内存拷贝和 dtype 转换——这点 eval 并不帮你省。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











