NumPy 运算比原生列表慢是因触发“退化模式”:np.vectorize 实为 for 循环包装器,dtype=object 放弃所有优化,小数组高频创建开销反超计算本身。

NumPy 运算比原生列表还慢,不是 bug,而是你触发了它的“退化模式”——它被迫回到 Python 解释器循环里干活,甚至比手写 for 还费劲。
np.vectorize 本质是假向量化
np.vectorize 看起来像向量化,实际只是个 for 循环包装器:它把你的 Python 函数逐个调用在每个元素上,不利用 C 层、不走 SIMD、不跳过类型检查。
- 真实行为等价于
[my_func(x) for x in arr],只是多了一层开销 - 一旦
my_func是纯 Python 函数(比如含if判断、调用math.sqrt),性能立刻崩盘 - 正确替代:用
np.where+ 原生 ufunc(如np.sqrt)、或改写为布尔索引 + 向量化表达式
dtype=object 让 NumPy 变成“最慢列表”
当你看到 arr.dtype == np.dtype("O"),就该警觉了——这表示 NumPy 放弃了所有优化,每个元素都要走 Python 对象协议。
快速生成专业的 Python 脚本和应用代码。一键创建完整项目结构,支持CLI、API、爬虫、Bot、Django等多种项目类型,包含完整的项目结构、配置文件、依赖管理、测试、README和文档。
- 常见诱因:
np.array([1, 2.0, "hello"])、np.array(list_of_dicts)、从 pandas DataFrame 混合列直接转数组 - 此时
arr + 1的性能可能比原生 list 推导式还差,因为多了数组元信息解析和对象分发开销 - 解法:初始化时强制指定 dtype(
np.array(data, dtype=np.float64)),或先清洗数据再转数组
小数组 + 高频创建 = NumPy 自己拖自己后腿
创建一个含 10 个元素的 np.ndarray,开销可能超过计算本身。Python 列表的 .append() 和内存预分配,在这种场景下反而更轻量。
立即学习“Python免费学习笔记(深入)”;
- 典型场景:循环中反复构建小数组(如
for i in range(1000): tmp = np.array([x, y, z])) - NumPy 的连续内存分配、dtype 推断、flags 初始化等固定成本,在
- 对策:避免在热循环内新建小数组;改用预分配大数组 + 索引赋值;或干脆用 tuple/list 存临时值
最容易被忽略的是:NumPy 的加速不是自动生效的,它只对“同质数据 + 连续内存 + ufunc 原语”起效。一旦其中任一条件破裂,它就从引擎变成累赘——而这种破裂往往悄无声息,只在 arr.flags.c_contiguous 为 False 或 arr.dtype 是 O 时才暴露出来。

















