20分钟用 NumPy 彻底搞懂线性代数核心-NumPy 线性代数核心详解 (np.linalg)
1. 理论速查表
| 函数/操作 | 数学符号 | 作用 | 通俗解释 | 关键限制 |
|---|---|---|---|---|
np.dot()/@ | 矩阵乘法 | 数据的“变换”与“组合”。深度学习的核心运算。 | A的列数 = B的行数 | |
np.vdot() | 向量点积 | 衡量两个向量的“相似度”或“投影”。 | 自动展平数组 | |
np.linalg.det() | $ | A | $ | 行列式 |
np.linalg.inv() | 逆矩阵 | 矩阵的“倒数”。用于解方程 $Ax=b$。 | 行列式不能为0 (满秩) | |
np.linalg.eig() | 特征值/向量 | 找出矩阵变换中“方向不变”的轴。 | 必须是方阵 |
2. 核心概念通俗解读
A. 矩阵乘法 (@或dot) —— 最重要的操作
- 是什么:不是对应元素相乘!它是**“行乘以列”**再求和。
- 有什么用:
- 它代表了空间的旋转、缩放或投影变换。
- 口诀:中间相同消掉,两边留下。
B. 行列式 (det) —— 矩阵的“体检指标”
- 是什么:一个标量(数字)。
- 含义:
- 如果 $|A| = 2$,说明这个矩阵把空间放大了2倍。
- 如果 $|A| = 0$,说明矩阵把空间“压扁”了(降维了),信息丢失了。
- 关键点:只有行列式不为0,矩阵才有逆矩阵。
C. 逆矩阵 (inv) —— 矩阵的“后悔药”
- 有什么用:
- 解方程:如果 $Ax = b$,那么 $x = A^{-1}b$。
- 如果你对一个图片做了变换 $A$,想还原它,就乘以 $A^{-1}$。
- 限制:如果行列式为0(奇异矩阵),就没有逆矩阵(无法还原)。
3. 完整实操演练
我们将创建一个具体的场景:模拟一个简单的神经网络层(矩阵乘法),并尝试解一个线性方程组(逆矩阵)。
import numpy as np print("="*40) print(" NumPy 线性代数实战演练") print("="*40) # --- 场景 1: 矩阵乘法 (深度学习的核心) --- # 假设我们有 2 个样本 (2行),每个样本有 3 个特征 (3列) inputs = np.array([ [1.0, 2.0, 3.0], # 样本 1 [4.0, 5.0, 6.0] # 样本 2 ]) # 假设神经网络的权重矩阵:3 个输入节点连接到 2 个输出节点 (3行 2列) weights = np.array([ [0.1, 0.2], # 特征1 的权重 [0.3, 0.4], # 特征2 的权重 [0.5, 0.6] # 特征3 的权重 ]) print("\n【1. 矩阵乘法 (Forward Pass)】") print("输入形状:", inputs.shape) # (2, 3) print("权重形状:", weights.shape) # (3, 2) # 方法 A: 使用 @ 符号 (推荐,Python 3.5+) outputs = inputs @ weights # 方法 B: 使用 np.dot (老写法,效果一样) # outputs = np.dot(inputs, weights) print("输出结果 (2个样本,每个2个输出):\n", outputs) # 计算逻辑示例 (第一行第一列): 1*0.1 + 2*0.3 + 3*0.5 = 0.1+0.6+1.5 = 2.2 # --- 场景 2: 行列式与逆矩阵 (解方程) --- # 假设我们要解方程组: # 1x + 2y = 5 # 3x + 4y = 11 # 写成矩阵形式 Ax = B A = np.array([[1, 2], [3, 4]]) B = np.array([5, 11]) print("\n【2. 行列式与逆矩阵】") print("系数矩阵 A:\n", A) # 2.1 计算行列式 det_A = np.linalg.det(A) print(f"A 的行列式 (det): {det_A:.2f}") # 解释: 1*4 - 2*3 = -2. 不为0,说明可逆。 if det_A != 0: # 2.2 计算逆矩阵 inv_A = np.linalg.inv(A) print("A 的逆矩阵 (inv):\n", inv_A) # 2.3 验证: A * A_inv 应该等于单位矩阵 I identity = A @ inv_A print("验证 (A @ A_inv):\n", identity) # 结果应该接近 [[1, 0], [0, 1]] (可能有微小浮点误差) # 2.4 解方程 x = A_inv * B # 注意: 解方程通常直接用 np.linalg.solve(A, B) 更稳定,但这里演示逆矩阵用法 x = inv_A @ B print(f"\n方程的解 x (通过逆矩阵计算): {x}") # 预期: x=1, y=2 (因为 1*1+2*2=5, 3*1+4*2=11) # 推荐的标准解法 (数值更稳定) x_best = np.linalg.solve(A, B) print(f"方程的解 x (推荐 solve 函数): {x_best}") else: print("行列式为0,矩阵不可逆,无法求解唯一解。") # --- 场景 3: 向量点积 (相似度) --- print("\n【3. 向量点积 (Vdot)】") vec1 = np.array([1, 0, 0]) # x轴方向 vec2 = np.array([0, 1, 0]) # y轴方向 vec3 = np.array([1, 1, 0]) # 45度方向 # 垂直向量点积应为 0 print(f"x轴 与 y轴 的点积 (应接近0): {np.vdot(vec1, vec2)}") # 同向分量越多,值越大 print(f"x轴 与 45度 的点积: {np.vdot(vec1, vec3)}") # 结果为 14. 运行结果解析
当你运行上述代码时,你会看到:
矩阵乘法:
- 输入是
(2, 3),权重是(3, 2)。 - 输出变成了
(2, 2)。这就是神经网络中“维度变换”的过程。
- 输入是
行列式与逆矩阵:
det结果是-2.0。说明这个变换把面积翻了2倍,并且翻转了方向(负号)。inv算出了逆矩阵。A @ inv_A的结果非常接近单位矩阵[[1, 0], [0, 1]](由于计算机浮点数精度,可能会看到0.99999或1e-16这种极小值,视为0)。- 最终解出 $x=1, y=2$,完美验证了方程。
点积:
- 垂直的向量点积为 0(正交)。
- 有夹角的向量点积反映了它们在某个方向上的投影长度。
避坑指南
*vs@:- 在 NumPy 中,
A * B是对应元素相乘(Element-wise)。 A @ B才是矩阵乘法(Matrix Multiplication)。千万别搞混!
- 在 NumPy 中,
- 形状不匹配:如果报错
shapes (2,3) and (2,3) not aligned,说明你试图做矩阵乘法,但前一个矩阵的列数 (3) 不等于后一个矩阵的行数 (2)。这时候检查是不是该用*或者转置.T。 - 奇异矩阵:如果
np.linalg.inv()报错Singular matrix,说明行列式为0,这个矩阵没有逆矩阵(通常意味着数据中有冗余特征,比如两列完全一样)。
