pin_drop当前位置:知识文库 ❯ 图文

NumPy数组运算详解 - 逐元素运算与矩阵乘法完整教程

一、数组运算概述

NumPy数组运算支持三大类操作:逐元素运算(加减乘除)、矩阵运算(点积、矩阵乘法)和聚合运算(求和、均值等)。NumPy的向量化运算避免了Python循环,利用底层C实现和SIMD指令实现高性能计算。理解数组运算的规则是高效使用NumPy的关键。

向量化运算的核心优势在于:

  • 高性能:底层C实现,运算速度比Python循环快数十到数百倍

  • 代码简洁:一行代码即可完成整个数组的运算

  • SIMD加速:利用CPU的向量化指令并行处理多个数据


二、逐元素运算符详解

逐元素运算(Element-wise Operation)是NumPy最基本的运算方式,对两个形状相同的数组,在对应位置上分别进行运算。每个运算符都有对应的NumPy函数:

运算符 对应函数 说明
+ np.add() 加法
- np.subtract() 减法
* np.multiply() 乘法(逐元素)
/ np.divide() 除法
// np.floor_divide() 整除
% np.mod() 取模
** np.power() 幂运算

三、矩阵运算函数

矩阵运算遵循线性代数规则,与逐元素运算完全不同。NumPy提供了多种矩阵运算函数:

函数/运算符 说明
np.dot(a, b) 点积(向量内积/矩阵乘法)
np.matmul(a, b) 矩阵乘法
a @ b 矩阵乘法运算符(Python 3.5+)
np.inner(a, b) 内积
np.outer(a, b) 外积
np.cross(a, b) 叉积

四、逐元素运算代码示例

下面演示最基本的逐元素运算,两个数组对应位置分别进行加减乘除等运算:

代码示例


import numpy as np

a = np.array([1, 2, 3, 4])
b = np.array([5, 6, 7, 8])

print(f"a = {a}")
print(f"b = {b}")
print(f"a + b = {a + b}")
print(f"a - b = {a - b}")
print(f"a * b = {a * b}")
print(f"a / b = {a / b}")
print(f"a ** 2 = {a ** 2}")
print(f"a % b = {a % b}")

输出结果:

代码示例


a = [1 2 3 4]
b = [5 6 7 8]
a + b = [ 6  8 10 12]
a - b = [-4 -4 -4 -4]
a * b = [ 5 12 21 32]
a / b = [0.2        0.33333333 0.42857143 0.5       ]
a ** 2 = [ 1  4  9 16]
a % b = [1 2 3 4]

五、矩阵运算代码示例

矩阵运算包括向量点积、矩阵乘法、外积等线性代数操作:

代码示例


import numpy as np

# 向量点积
v1 = np.array([1, 2, 3])
v2 = np.array([4, 5, 6])
print(f"向量点积: {np.dot(v1, v2)}")
print(f"@运算符: {v1 @ v2}")

# 矩阵乘法
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
print(f"\n矩阵A:\n{A}")
print(f"矩阵B:\n{B}")
print(f"A @ B:\n{A @ B}")
print(f"np.matmul:\n{np.matmul(A, B)}")

# 外积
print(f"\n外积:\n{np.outer(v1, v2)}")

输出结果:

代码示例


向量点积: 32
@运算符: 32

矩阵A:
[[1 2]
 [3 4]]
矩阵B:
[[5 6]
 [7 8]]
A @ B:
[[19 22]
 [43 50]]
np.matmul:
[[19 22]
 [43 50]]

外积:
[[ 4  5  6]
 [ 8 10 12]
 [12 15 18]]

提示:向量点积的计算方式为 1×4 + 2×5 + 3×6 = 4 + 10 + 18 = 32。矩阵乘法中,A@B的第一行第一列元素 = 1×5 + 2×7 = 19,以此类推。

六、标量运算与原地操作

标量运算将单个数值应用到数组的每个元素。原地操作(+=、*=等)会直接修改原数组,节省内存分配开销:

代码示例


import numpy as np

arr = np.array([1, 2, 3, 4, 5])

# 标量运算
print(f"arr + 10 = {arr + 10}")
print(f"arr * 2 = {arr * 2}")
print(f"arr / 2 = {arr / 2}")
print(f"arr ** 3 = {arr ** 3}")

# 原地操作(修改原数组)
arr2 = np.array([1, 2, 3, 4, 5])
arr2 += 10
print(f"\narr2 += 10: {arr2}")
arr2 *= 2
print(f"arr2 *= 2: {arr2}")

# 比较运算
arr3 = np.array([1, 2, 3, 4, 5])
print(f"\narr3 > 3: {arr3 > 3}")
print(f"arr3 == 3: {arr3 == 3}")
print(f"np.equal(arr3, 3): {np.equal(arr3, 3)}")

输出结果:

代码示例


arr + 10 = [11 12 13 14 15]
arr * 2 = [ 2  4  6  8 10]
arr / 2 = [0.5 1.  1.5 2.  2.5]
arr ** 3 = [  1   8  27  64 125]

arr2 += 10: [11 12 13 14 15]
arr2 *= 2: [22 24 26 28 30]

arr3 > 3: [False False False  True  True]
arr3 == 3: [False False  True False False]
np.equal(arr3, 3): [False False  True False False]

小贴士

比较运算(>、<、== 等)返回布尔数组,这在数据过滤中非常有用。例如 arr[arr > 3] 可以直接筛选出大于3的元素。


七、运算类型对比

运算类型 运算符 说明 示例
逐元素加法 + 对应位置相加 [1,2]+[3,4]=[4,6]
逐元素乘法 * 对应位置相乘 [1,2]*[3,4]=[3,8]
矩阵乘法 @ 线性代数乘法 [[1,2],[3,4]]@[[5,6],[7,8]]
标量运算 +,-,*,/ 每个元素与标量运算 [1,2,3]*2=[2,4,6]

八、实际应用场景

  • 数据归一化:使用标量运算将数据缩放到0-1范围,公式为 (x - min) / (max - min)

  • 神经网络前向传播:使用矩阵乘法计算线性变换 y = Wx + b

  • 金融计算:使用逐元素运算计算收益率、移动平均等技术指标

九、注意事项

注意:* 运算符是逐元素乘法,不是矩阵乘法;矩阵乘法必须使用 @np.dot()

注意:整数除法使用 //,普通 / 运算在NumPy中始终返回浮点数

注意:原地操作(+=、*=)会修改原数组,非原地操作(+、*)返回新数组。原地操作可以节省内存,但会丢失原始数据。


常见问题

NumPy中 * 和 @ 有什么区别?

* 是逐元素乘法(对应位置相乘),@ 是矩阵乘法(遵循线性代数规则)。例如 [1,2]*[3,4]=[3,8],而矩阵乘法需要满足内维度相等的条件。

原地操作 += 会提高性能吗?

是的,原地操作避免了新数组的内存分配和数据复制,可以节省内存和减少GC压力。在大规模数据处理时效果明显,但会修改原始数据。

np.dot() 和 np.matmul() 有什么区别?

对于2D矩阵两者等价。但np.dot()在输入是一维时计算向量内积,高维时行为不同;np.matmul()始终按矩阵乘法规则处理,不支持标量乘法。推荐使用@运算符,语义最清晰。

数组运算时形状不匹配怎么办?

可以使用NumPy的广播机制,或使用reshape调整形状。如果两个数组完全无法广播,需要先通过reshape、newaxis等方式使其形状兼容。

如何实现数据归一化?

使用公式 (arr - arr.min()) / (arr.max() - arr.min())。这里利用了标量运算和逐元素运算,一行代码即可完成整个数组的归一化。


标签: NumPy 数组运算 矩阵乘法 逐元素运算 Python教程 向量化

本文涉及AI创作

内容由AI创作,请仔细甄别

list快速访问

上一篇: NumPy数组形状操作教程 - reshape、flatten、transpose详解 下一篇: NumPy广播机制详解 - 不同形状数组运算规则完整教程

poll相关推荐