📢 转载信息
原文链接:https://machinelearningmastery.com/7-numpy-tricks-to-vectorize-your-code/
原文作者:Jason Brownlee
🚀 7个Numpy技巧,助你彻底向量化代码,大幅提升性能!
在数据科学和机器学习领域,Numpy无疑是Python中最核心的库之一。然而,许多初学者仍然习惯于使用Python的循环(loops)来处理数组,这在处理大型数据集时效率极低。
向量化(Vectorization)是Numpy的精髓,它利用底层C语言的优化,使数组操作比逐个元素处理快得多。本文将介绍7个强大的Numpy技巧,帮助你摆脱低效的循环,让你的代码运行速度得到质的飞跃。

1. 避免循环:使用 `np.where()` 代替条件判断
当你在处理数组时需要根据条件进行赋值,比如“如果满足条件A,则取值X;否则取值Y”,很多人会想到使用Python的if/else
语句放在循环中。Numpy提供了更简洁高效的np.where()
函数来完成这项任务。
低效示例(使用循环):
# 假设我们有一个数组a
a = np.array([1, 5, -3, 10, -2, 8])
b = np.zeros_like(a)
for i in range(len(a)):
if a[i] > 0:
b[i] = a[i] * 2
else:
b[i] = a[i] / 2
高效向量化示例(使用 `np.where()`):
a = np.array([1, 5, -3, 10, -2, 8])
b = np.where(a > 0, a * 2, a / 2)
print(b)
# 输出: [ 2. 10. -1.5 20. -1. 16. ]
np.where(condition, x, y)
会根据条件返回x或y的对应元素,完全避免了Python级别的循环开销。
2. 使用布尔索引进行高效筛选
如果你想根据条件从数组中提取元素,避免使用循环或列表推导式。布尔索引(Boolean Indexing)是实现这一目标的原生Numpy方式。
低效示例:
a = np.array([1, 5, -3, 10, -2, 8])
positive_numbers = []
for x in a:
if x > 0:
positive_numbers.append(x)
高效向量化示例:
a = np.array([1, 5, -3, 10, -2, 8])
positive_mask = a > 0 # 生成布尔数组
positive_numbers = a[positive_mask]
# 或者直接:
positive_numbers = a[a > 0]
print(positive_numbers)
# 输出: [ 1 5 10 8]
3. 广播(Broadcasting)的力量
广播是Numpy最强大、最难以理解但却至关重要的特性之一。它允许不同形状的数组进行算术运算,而无需显式地复制数据。
例如,将一个标量(单个数字)加到一个Numpy数组的所有元素上,或者将一个1D数组与一个2D数组的每一行相加,Numpy都会自动“广播”该操作。
A = np.array([[1, 2, 3],
[4, 5, 6]])
# 广播一个标量
B = A + 10
print(B)
# 输出:
# [[11 12 13]
# [14 15 16]]
# 广播一个一维数组到矩阵的每一行
C = np.array([100, 200, 300])
D = A + C
print(D)
# 输出:
# [[101 202 303]
# [104 205 306]]
4. 避免不必要的内存拷贝:使用视图
在Numpy中,切片(slicing)通常不会创建数据的副本,而是返回原始数组的一个“视图”(View)。修改视图会直接修改原始数组,这极大地节省了内存和时间。
你需要知道什么时候操作返回的是视图,什么时候返回的是副本。例如,简单的切片返回视图,但使用布尔索引或整数索引返回副本。
# 返回视图的例子
original = np.arange(10)
view = original[2:5] # 视图
view[:] = 999 # 修改视图
print(original)
# 输出: [ 0 1 999 999 999 5 6 7 8 9]
# 返回副本的例子
copy_slice = original[original > 5] # 副本
copy_slice[:] = 111
print(original) # 原始数组未变
# 输出: [ 0 1 999 999 999 5 6 7 8 9]
5. 矩阵乘法:使用 `@` 运算符
如果你需要进行矩阵乘法(线性代数中的点积),请避免使用嵌套循环。在Python 3.5及更高版本中,推荐使用简洁的@
运算符,它对应于np.matmul()
。
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
# 向量化操作
C = A @ B
print(C)
# 输出:
# [[19 22]
# [43 50]]
6. 使用 `np.ufunc` 进行元素级操作
通用函数(Universal Functions,ufuncs)是Numpy处理数组的标准方式,比如np.add()
, np.sqrt()
, np.sin()
等。它们都经过高度优化,并且支持广播。
永远不要在Numpy数组上循环来计算这些基本数学函数。
a = np.array([1.0, 4.0, 9.0])
# 向量化平方根
result = np.sqrt(a)
print(result)
# 输出: [1. 2. 3.]
7. 利用 `np.meshgrid` 创建坐标网格
在需要对二维空间中的每个点进行计算时(例如在绘图或物理模拟中),np.meshgrid
是一个强大的工具,它可以生成坐标矩阵,避免了嵌套循环。
# 假设我们要计算 x^2 + y^2 在 x=[-2, -1, 0, 1, 2] 和 y=[-2, -1, 0, 1, 2] 上的值
x = np.array([-2, -1, 0, 1, 2])
y = np.array([-2, -1, 0, 1, 2])
# 创建网格坐标矩阵
X, Y = np.meshgrid(x, y)
# 直接在矩阵上进行向量化计算
Z = X**2 + Y**2
print("X 矩阵:\n", X)
print("Y 矩阵:\n", Y)
print("Z 结果:\n", Z)
通过使用X
和Y
这两个矩阵,我们一次性完成了5x5=25个点的计算,效率远高于使用两个嵌套for
循环。
总结
掌握Numpy的向量化编程是成为高效数据科学家的必经之路。当你看到自己写下for i in range(len(array)):
时,请立即停下来思考:Numpy是否有内置函数或广播机制可以替代这段代码? 坚持使用这些技巧,你的代码性能将会显著提升!
🚀 想要体验更好更全面的AI调用?
欢迎使用青云聚合API,约为官网价格的十分之一,支持300+全球最新模型,以及全球各种生图生视频模型,无需翻墙高速稳定,小白也可以简单操作。
青云聚合API官网https://api.qingyuntop.top
支持全球最新300+模型:https://api.qingyuntop.top/pricing
详细的调用教程及文档:https://api.qingyuntop.top/about
评论区