You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

pd.eval/pd.query使用numexpr引擎时如何调用自定义函数筛选行

问题复现

初始测试代码:

import pandas as pd
def f(a):
    print(a)
    if a%2==0:
        return True
    else:
        return False
temp = pd.DataFrame({'hello':[1,2,3,4]})

执行以下代码时会触发报错:

pd.eval("temp.hello.apply(f)")

报错内容:

TypeError: unhashable type: 'Series'

指定engine='python'参数后代码可正常运行:

pd.eval("temp.hello.apply(f)",engine = 'python')

运行输出:

0    False
1     True
2    False
3     True
Name: hello, dtype: bool

待解决需求:使用自定义逻辑实现数据行筛选,同时保留numexpr引擎的速度优势。

问题原因

numexpr引擎的底层实现不支持调用Python层面定义的自定义逐行函数。它的工作逻辑是把传入的表达式编译为面向CPU缓存优化的底层数组运算指令,全程不触发Python逐行循环的开销。如果直接把自定义Python函数写进pd.eval的表达式里,numexpr无法把函数逻辑转译成本地运算指令,会把整个Series对象作为单个参数传入函数,最终触发类型报错。
而python引擎本质就是直接在Python环境里执行传入的表达式,支持任意Python语法,包括逐行apply自定义函数,但因为走Python逐行循环,完全没有numexpr的速度优势。

实现方案

要保留numexpr的速度优势,核心原则是不要把自定义Python函数放到pd.eval的执行流里,把自定义逻辑转化为numexpr支持的原生向量化运算即可,具体操作分几种场景:

  • 简单判断逻辑直接转写为向量化表达式
    比如示例中判断数值是否为偶数的逻辑,完全不需要定义单独的f函数、也不需要用apply,直接把判断逻辑写进eval表达式即可,全程由numexpr加速:
    # 生成筛选所用的布尔掩码,运算过程走numexpr加速
    filter_mask = pd.eval("temp.hello % 2 == 0", engine="numexpr")
    # 完成行筛选
    filtered_df = temp[filter_mask]
    
  • 带分支的复杂逻辑拆分为多段向量化条件,用位运算组合
    如果你的自定义函数包含多分支判断,把每个分支的判断条件拆成独立的向量化运算,再用&(与)、|(或)、~(非)组合成最终的筛选掩码,所有运算环节都可以交给numexpr执行:
    # 示例:筛选hello列大于等于2、且为偶数的行
    cond_ge2 = pd.eval("temp.hello >= 2", engine="numexpr")
    cond_even = pd.eval("temp.hello % 2 == 0", engine="numexpr")
    filter_mask = pd.eval("cond_ge2 & cond_even", engine="numexpr")
    filtered_df = temp[filter_mask]
    
  • 无法转成向量化运算的特殊逻辑,做分层处理
    如果你的自定义逻辑包含numexpr无法支持的操作(比如调用外部依赖、复杂的非向量化字符串处理),先单独用Python函数处理这部分极小占比的逻辑,输出结果存为Series/数组后,再把后续批量判断、筛选的环节交给numexpr执行,尽可能压缩Python逐行运算的占比,最大化速度收益。

不要尝试强行让numexpr支持Python自定义函数:numexpr的速度优势本身就来自于跳过Python层的逐行调用,一旦在运算流里插入Python自定义函数,就会打破它的批量运算优化,哪怕能跑也和python引擎的速度没有区别,失去了用numexpr的意义。

内容的提问来源于stack exchange,提问作者Lokin Sethia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 19:18:26