迁移至Python3后pandas eval结合where函数报错排查
问题解答
报错原因
这个错误不是Python3迁移直接导致,而是伴随Python3升级时pandas版本更新引发的行为变化。原代码中:
val_per函数接收的ASSET和PRODUCT是numpy数组(由MAIN_df.eval传递列数据时生成)pd.eval在处理这些数组参数时,会尝试将它们存入内部的命名空间字典,而numpy数组属于不可哈希类型,无法作为字典的键,因此抛出TypeError。
解决方案
无需在where中嵌套pd.eval,直接对numpy数组进行向量化布尔运算即可,既解决报错又提升效率:
修改后的代码
import pandas as pd, numpy as np from numpy import where, nan d = {'ASSET': ['X','X','A','X','B'], 'PRODUCT': ['Z','Y','Z','C','Y']} MAIN_df = pd.DataFrame(data=d) def val_per(ASSET, PRODUCT): # 直接用numpy数组的布尔运算替代pd.eval return where((ASSET == 'X') & (PRODUCT == 'Z'), 0.04, where(PRODUCT == 'Y', 0.08, 1.5)) MAIN_2_df = MAIN_df.assign(PCT=val_per(MAIN_df['ASSET'].values, MAIN_df['PRODUCT'].values))
更简洁的写法(无需自定义函数)
直接在assign中完成逻辑,避免函数调用的额外开销:
MAIN_2_df = MAIN_df.assign( PCT=np.where( (MAIN_df['ASSET'] == 'X') & (MAIN_df['PRODUCT'] == 'Z'), 0.04, np.where(MAIN_df['PRODUCT'] == 'Y', 0.08, 1.5) ) )
补充说明
- 原代码中使用
MAIN_df.eval("@val_per(ASSET, PRODUCT)")的方式,在旧版pandas中可能通过兼容逻辑绕过了哈希检查,但新版pandas严格遵循字典键必须可哈希的规则,因此触发报错。 - 向量化运算(直接操作numpy数组)是pandas/numpy的最优实践,比嵌套
pd.eval的效率更高,代码可读性也更强。
内容的提问来源于stack exchange,提问作者DisplayNumber
相关产品推荐
相关产品推荐

