pandas.eval 默认不修改原 dataframe,仅返回计算结果;需手动赋值如 df["col"] = df.eval("a + b") 才能更新列。

eval 会改原 DataFrame 吗?
pandas.eval 默认不修改原数据,它只返回计算结果。想“原位修改”,得手动赋值——很多人卡在这儿,以为写了 df.eval("col = a + b") 就自动更新了列,其实没用。
常见错误现象:df.eval("col = a + b") 执行后 df 完全没变;或者返回一个 Series 或标量,但不知道往哪儿塞。
- 正确做法是:用
df["col"] = df.eval("a + b")(生成新列)或df.loc[:, "col"] = df.eval("a + b")(显式定位) - 如果真想“就地赋值”且避免中间变量,可配合
inplace=True的等效写法——但注意:eval本身没有inplace参数,必须靠赋值模拟 - 别对
df.eval("col = a + b")的返回值掉以轻心:它返回的是右值(即a + b的结果),不是df
哪些运算符和函数 eval 支持?
pandas.eval 不是 Python 全功能解释器,它只支持子集:基础算术(+, -, *, /, **)、比较(==, !=, , <code>in)、布尔逻辑(&, |, ~),以及少量内置函数如 sin, cos, log, exp, abs。
使用场景:快速做列间算术、条件筛选(比如 df.query 底层就用它),但别指望调 np.where 或自定义函数。
-
df.eval("a * b + np.log(c)")❌ 报NameError: name 'np' is not defined——np不在默认命名空间里 -
df.eval("log(c)")✅ 可用,因为log是内置函数(底为 e) -
df.eval("a in [1, 2, 3]")❌ 不支持列表字面量,但df.eval("a == 1 or a == 2 or a == 3")✅
eval 和直接 Python 运算比,快在哪?
快在避免 Python 字节码解释开销,尤其对大 DataFrame:它把表达式编译成 NumPy 级别的向量化操作,跳过逐行 Python 循环。但提速有前提——不能混用 Python 对象或触发回退(fallback)。
性能影响关键点:一旦表达式里出现不支持的语法(比如字符串方法、lambda、括号嵌套过深),eval 会静默切回标准 Python 求值,这时反而更慢,还失去内存优势。
- 推荐用
engine="numexpr"(默认):适合数值密集型,内存友好 - 若含大量字符串操作,不如直接用
.str链式调用,eval压根不支持.str.contains这类 - 测试是否真加速?别猜,用
%timeit df.eval("a + b")和%timeit df["a"] + df["b"]实测——小数据下可能差不多甚至更慢
为什么有时 eval 报 KeyError 或 UndefinedVariableError?
不是列名写错了,而是作用域问题:eval 默认只认 DataFrame 的列名,不认外部变量,也不认局部作用域里的 dict 或临时变量。
常见错误现象:threshold = 10; df.eval("a > threshold") 直接报 UndefinedVariableError;或者用了 df.eval("a > @threshold") 却忘了加 @ 符号。
- 引用外部变量必须加
@前缀:df.eval("a > @threshold") - 引用另一个 DataFrame 的列?不行,
eval只绑定单个df;跨表要用merge或join先对齐 - 列名含空格或特殊字符?必须用反引号:
df.eval("`user id` > 100")
事情说清了就结束。最常被忽略的是作用域规则和回退机制——看着代码跑通了,其实早切到慢路径上,还误以为是 eval 在起作用。










