调用pd.read_sql后传入p参数的np.random.choice抛出异常
问题原因
这是NumPy 1.22.x系列版本的已知兼容问题:调用pd.read_sql时,底层用到的数据库驱动(如pyodbc、pymssql等)会加载与NumPy C扩展存在ABI冲突的旧版C运行时,破坏NumPy全局随机数生成器的内部校验逻辑。np.random.choice传入p参数时,内部会先校验概率数组的合法性、校验概率和是否为1,全局状态被破坏后,哪怕传入完全合规的概率数组,也会被误判为非法值抛出异常。
问题特征
- 无
p参数的np.random.choice(5, 3)可正常运行
- 传入任意合法
p参数都会触发异常,示例调用:np.random.choice(5, 3, p=[0.1, 0, 0.3, 0.6, 0])
- 触发时机固定:执行
pd.read_sql前带p参数的调用完全正常,执行完该语句后立刻复现报错 - 复现环境:
- Python 3.10.0

- NumPy 1.22.4(撰写时的最新正式版)

- Python 3.10.0
- 所有调用写法完全符合NumPy接口规范,不存在参数传错的问题。
解决方法
按优先级选择任意一种即可修复:
- 升级NumPy到1.23.0及以上版本,该版本已经修复了第三方库篡改C运行时状态后的校验异常问题,执行命令
pip install --upgrade numpy完成升级 - 暂时无法升级NumPy的话,不要使用全局随机数接口,显式创建独立的随机数生成器实例即可,该实例不受全局状态破坏影响:
# 替代原np.random.choice调用 rng = np.random.default_rng() res = rng.choice(5, 3, p=[0.1, 0, 0.3, 0.6, 0]) - 升级pandas到1.4.4及以上版本,新版本调整了
read_sql加载数据库驱动时的C库加载顺序,不会再篡改NumPy依赖的运行时状态 - 如果使用pyodbc作为数据库连接驱动,升级pyodbc到4.0.35及以上版本即可修复C运行时链接的兼容问题
内容的提问来源于stack exchange,提问作者DJ_
相关产品推荐
相关产品推荐

