pd.eval() 通常比普通运算快,但仅当数据量大(>10⁵行)、多列表达式且启用numexpr时才明显;小数据因解析开销反而更慢。

eval函数在Pandas中真的更快吗?
多数情况下,pd.eval() 比直接用 df['a'] + df['b'] * df['c'] 快,但仅当数据量大(通常 > 10⁵ 行)、表达式含多个列运算、且未启用 numexpr 后端时才明显。它底层调用 numexpr 做向量化计算和内存优化,跳过 Python 解释器开销。但小数据集反而更慢——因为启动解析和编译有固定开销。
验证方法很简单:
import pandas as pd<br>import time<br>df = pd.DataFrame({'a': range(10**6), 'b': range(10**6), 'c': range(10**6)})<br><br># 方法1:普通运算<br>t1 = time.time()<br>df['x'] = df['a'] + df['b'] * df['c']<br>print(f"普通运算: {time.time() - t1:.4f}s")<br><br># 方法2:pd.eval<br>t2 = time.time()<br>df['y'] = pd.eval("a + b * c")<br>print(f"pd.eval: {time.time() - t2:.4f}s")
哪些表达式能用pd.eval,哪些会报错?
pd.eval() 支持基础算术、布尔比较、部分函数(如 sin、log、abs),但不支持任意 Python 代码。常见踩坑点:
- 不能调用自定义函数或
lambda—— 报NotImplementedError: "func" is not supported - 不能用
in、is、赋值语句(=)、三元表达式(x if cond else y) - 字符串方法(如
.str.contains())不可用;要用str.contains需显式启用engine='python',但此时几乎没加速 - 列名含空格或特殊字符必须用反引号包裹:
pd.eval("`col name` > 5")
如何安全启用多线程和内存优化?
pd.eval() 默认使用 numexpr 引擎,自动利用多核,但需确认环境已安装并启用:
- 检查是否启用:
pd.eval("1 + 1", engine='numexpr')不报错即支持;若报ValueError: engine must be 'numexpr' or 'python',说明numexpr未安装,运行pip install numexpr - 控制线程数(避免争抢):
import numexpr as ne; ne.set_num_threads(4) - 大数据慎用
parser='python':它退化为标准 Python 解析,速度可能比原生 Pandas 还慢 - 避免重复解析同一表达式:对循环中固定表达式,提前用
pd.eval(..., inplace=False)计算一次,不要在循环里反复调用
替代方案:什么时候该放弃eval,换别的写法?
当遇到以下情况,pd.eval() 不仅不快,还增加维护成本:
- 表达式逻辑复杂(嵌套条件、多分支)→ 改用
np.select()或df.assign().pipe()链式处理 - 需要访问行索引或位置信息(如
df.index)→pd.eval()默认不暴露index,得手动传入:pd.eval("a + index", local_dict={'index': df.index}),易出错 - 涉及
groupby后的列运算 → 先transform或agg,再用eval,别试图在eval里写groupby - 使用
category或nullable int类型时,eval可能隐式转成object或float64,丢失类型信息
真正省时间的地方,往往不是换一个函数,而是减少中间 DataFrame 拷贝、复用已有列引用、以及把多次 eval 合并成一次多输出表达式(如 pd.eval("x = a+b; y = b*c"))。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











