第 10 章 线性代数
学习目标
- 区分逐元素乘法与矩阵乘法
- 掌握
@运算符与np.dot - 掌握逆矩阵、行列式与矩阵秩
- 会用
np.linalg.solve解线性方程组 - 认识特征值与最小二乘(选学)
10.1 矩阵乘法 vs 逐元素乘法
第 4 章的 * 是逐元素乘法;线性代数里的矩阵乘法是另一回事:结果矩阵的 [i, j] 位置 = 左矩阵第 i 行与右矩阵第 j 列的对应元素乘积之和。
NumPy 用 @ 运算符(或 np.dot)做矩阵乘法:
import numpy as np
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
print(A * B) # 逐元素乘法
print(A @ B) # 矩阵乘法
print(np.dot(A, B)) # 与 @ 等价输出:
[[ 5 12]
[21 32]]
[[19 22]
[43 50]]
[[19 22]
[43 50]]对照验证 A @ B 的 [0, 0] 位置:1×5 + 2×7 = 19,与输出一致。
形状规则:两个矩阵 (m, n) 与 (n, p) 可以相乘,结果是 (m, p);A @ B 要求 A 的列数等于 B 的行数,否则报错:
>>> np.array([[1, 2, 3]]) @ np.array([[4, 5]])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: matmul: Input operand 1 has a mismatch in its core dimension 0, with gufunc signature (n?,k),(k,m?)->(n?,m?)一维数组与矩阵相乘,结果是矩阵作用于向量(每个位置 = 行向量点乘该向量):
import numpy as np
A = np.array([[1, 2], [3, 4]])
v = np.array([1, 2])
print(A @ v) # A 的每一行与 v 点乘输出:
[ 5 11]10.2 单位矩阵与逆矩阵
单位矩阵(np.eye(n))是矩阵乘法的「1」:任何矩阵乘以单位矩阵不变。
逆矩阵 A⁻¹ 满足 A @ A⁻¹ = I。用 np.linalg.inv 求:
import numpy as np
A = np.array([[2, 1], [1, 3]])
inv = np.linalg.inv(A)
print(inv)
print(A @ inv) # 应接近单位矩阵输出:
[[ 0.6 -0.2]
[-0.2 0.4]]
[[ 1.00000000e+00 0.00000000e+00]
[-5.55111512e-17 1.00000000e+00]]A @ inv 的对角线是 1,非对角线是 -5.5e-17——浮点误差,近似 0,可以认为是单位矩阵。这正是「诚实」的输出:数学上是精确的 I,计算机浮点算出来带微小误差。
行列式 np.linalg.det 为 0(或接近 0)的矩阵不可逆,叫奇异矩阵:
import numpy as np
A = np.array([[2, 1], [1, 3]])
print(np.linalg.det(A))输出:
5.000000000000001行列式非零(≈5)说明可逆。对奇异矩阵求逆报 LinAlgError:
>>> np.linalg.inv(np.array([[1, 2], [2, 4]]))
Traceback (most recent call last):
...
numpy.linalg.LinAlgError: Singular matrix10.3 解线性方程组
线性方程组如:
2x + y = 5
x + 3y = 10写成矩阵形式 A x = b,其中 A = [[2, 1], [1, 3]],b = [5, 10]。用 np.linalg.solve(A, b) 求解:
import numpy as np
A = np.array([[2, 1], [1, 3]])
b = np.array([5, 10])
x = np.linalg.solve(A, b)
print(x) # x = 1, y = 3
print(A @ x) # 验证:应等于 b输出:
[1. 3.]
[ 5. 10.]x[0]=1、x[1]=3,代回检验:2×1+3=5,1+3×3=10,正确。验证步骤建议每次都要做:A @ x 应等于 b。
三元方程组同理:
import numpy as np
# x + y + z = 6
# 2y + 5z = -4
# 2x + 5y - z = 27
A = np.array([[1, 1, 1],
[0, 2, 5],
[2, 5, -1]])
b = np.array([6, -4, 27])
x = np.linalg.solve(A, b)
print(x)输出:
[ 5. 3. -2.]10.4 特征值与特征向量(选学)
特征值和特征向量是方阵的核心性质,用于主成分分析(PCA)、图像压缩等。np.linalg.eig(A) 返回两个数组:特征值 w 与特征向量矩阵 v:
import numpy as np
A = np.array([[2, 1], [1, 3]])
w, v = np.linalg.eig(A)
print(w) # 特征值
print(v) # 特征向量(每列一个)输出:
[1.38196601+0.j 3.61803399+0.j]
[[-0.85065081+0.j -0.52573111+0.j]
[ 0.52573111+0.j -0.85065081+0.j]]+0.j 表示虚部为 0 的复数,说明特征值是实数。入门只需知道:特征值衡量矩阵沿对应特征向量方向的「拉伸倍数」,eig 返回的值排序不固定。
10.5 最小二乘拟合(选学)
最小二乘(np.linalg.lstsq) 找一条直线 y = kx + c,使残差平方和最小——没有精确解或方程个数多于未知数时用它。
拟合 5 个点的线性趋势:
import numpy as np
xdata = np.array([1, 2, 3, 4, 5])
ydata = np.array([3.1, 4.9, 7.2, 8.8, 11.0])
# 设计矩阵:每行是 [x, 1],用于拟合 y = k*x + c
M = np.vstack([xdata, np.ones(5)]).T
k, c = np.linalg.lstsq(M, ydata, rcond=None)[0]
print("斜率 k:", k)
print("截距 c:", c)输出:
斜率 k: 1.9699999999999993
截距 c: 1.0900000000000019得到 y ≈ 1.97x + 1.09。lstsq 返回元组,取 [0] 是系数数组;rcond=None 是推荐的默认设置(控制奇异值截断)。
动手实践
- 手算
[[1, 2], [3, 4]] @ [[5, 6], [7, 8]]的[1, 0]位置,再用代码验证。 - 验证单位矩阵性质:任取一个 3×3 矩阵
M,检查M @ np.eye(3)与M相等。 - 解方程组
3x + 2y = 12、x - y = 1,写出 A 与 b,用solve求解并用A @ x验证。 - 对一个奇异矩阵求逆,记录报错信息,再打印它的行列式确认接近 0。
常见错误
| 错误写法 | 现象 | 原因 |
|---|---|---|
用 * 计算矩阵乘法 | 结果是逐元素乘积 | 矩阵乘法用 @ 或 np.dot |
A @ B 形状不匹配 | ValueError: matmul: Input operand 1 has a mismatch... | A 的列数必须等于 B 的行数 |
对奇异矩阵 inv | LinAlgError: Singular matrix | 行列式为 0 的矩阵不可逆 |
lstsq 结果直接打印 | 返回元组 | 取 [0] 得到系数数组 |
eig 结果里有 +0.j 就以为错了 | 特征值含虚部 0 的复数 | 实矩阵特征值以复数形式返回,虚部 0 即实数 |
solve 后不验证 | 手算错误没发现 | 养成 A @ x 验证的习惯 |
章末练习
基础
- 计算
[[1, 0], [0, 1]] @ [[3, 4], [5, 6]],说明结果与什么相同。 - 用
@计算两个 2×2 矩阵的乘积,并与*的结果对比。 - 求
[[3, 1], [1, 2]]的逆矩阵,并验证A @ inv ≈ I。
提高
- 解方程组
x + 2y = 8、3x + y = 9,给出 A、b、解,并用A @ x验证。 - 判断
[[2, 4], [1, 2]]是否可逆(先算行列式),再尝试求逆,记录结果。
挑战
- 用
lstsq拟合抛物线y = ax² + bx + c(提示:设计矩阵每行为[x², x, 1]),对给定数据求系数并评估拟合质量。 - 三阶矩阵特征值:求
[[2, 1, 0], [1, 3, 1], [0, 1, 2]]的特征值,验证np.linalg.eig的特征值之和等于矩阵的迹(对角线之和)。
章末自测
每题选择一个最佳答案。本书不附答案:完成后交由老师或 AI 老师批改讲解。
np.array([[1, 2], [3, 4]]) * np.array([[1, 1], [1, 1]])的结果是?- A.
[[3, 7]] - B.
[[1, 2], [3, 4]] - C.
[[2, 4], [6, 8]] - D. 报错
- A.
- 矩阵乘法应使用哪个运算符?
- A.
* - B.
@ - C.
# - D.
&
- A.
np.array([[1, 2]]) @ np.array([[1], [2]])的结果是?- A.
[[5]] - B.
5 - C.
[[1, 4]] - D. 报错
- A.
- 行列式为 0 的矩阵叫做?
- A. 单位矩阵
- B. 奇异矩阵
- C. 对角矩阵
- D. 对称矩阵
- 对奇异矩阵求逆会?
- A. 返回全 0
- B. 报
LinAlgError: Singular matrix - C. 返回单位矩阵
- D. 返回 nan
- 解方程组
A x = b应使用?- A.
np.linalg.inv直接左乘 - B.
np.linalg.solve(A, b) - C.
np.dot(A, b) - D.
A * b
- A.
np.linalg.solve之后验证结果的方法是?- A.
A @ x应等于 b - B.
x @ A应等于 b - C.
A * x应等于 b - D. 无法验证
- A.
A @ v(A 是 m×n,v 是长度 n)的结果是?- A. m×n 矩阵
- B. 长度 m 的向量
- C. 标量
- D. 报错
np.linalg.det返回的是?- A. 矩阵的秩
- B. 矩阵的行列式
- C. 矩阵的逆
- D. 矩阵的特征值
lstsq的用途是?- A. 求矩阵的行列式
- B. 找使残差平方和最小的拟合系数
- C. 解任意非线性方程
- D. 计算矩阵的特征值
