Skip to content

第 10 章 线性代数

学习目标

  • 区分逐元素乘法与矩阵乘法
  • 掌握 @ 运算符与 np.dot
  • 掌握逆矩阵、行列式与矩阵秩
  • 会用 np.linalg.solve 解线性方程组
  • 认识特征值与最小二乘(选学)

10.1 矩阵乘法 vs 逐元素乘法

第 4 章的 * 是逐元素乘法;线性代数里的矩阵乘法是另一回事:结果矩阵的 [i, j] 位置 = 左矩阵第 i 行与右矩阵第 j 列的对应元素乘积之和。

NumPy 用 @ 运算符(或 np.dot)做矩阵乘法:

python
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?)

一维数组与矩阵相乘,结果是矩阵作用于向量(每个位置 = 行向量点乘该向量):

python
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 求:

python
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)的矩阵不可逆,叫奇异矩阵:

python
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 matrix

10.3 解线性方程组

线性方程组如:

2x +  y = 5
 x + 3y = 10

写成矩阵形式 A x = b,其中 A = [[2, 1], [1, 3]],b = [5, 10]。用 np.linalg.solve(A, b) 求解:

python
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]=1x[1]=3,代回检验:2×1+3=5,1+3×3=10,正确。验证步骤建议每次都要做:A @ x 应等于 b

三元方程组同理:

python
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:

python
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 个点的线性趋势:

python
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.09lstsq 返回元组,取 [0] 是系数数组;rcond=None 是推荐的默认设置(控制奇异值截断)。

动手实践

  1. 手算 [[1, 2], [3, 4]] @ [[5, 6], [7, 8]][1, 0] 位置,再用代码验证。
  2. 验证单位矩阵性质:任取一个 3×3 矩阵 M,检查 M @ np.eye(3)M 相等。
  3. 解方程组 3x + 2y = 12x - y = 1,写出 A 与 b,用 solve 求解并用 A @ x 验证。
  4. 对一个奇异矩阵求逆,记录报错信息,再打印它的行列式确认接近 0。

常见错误

错误写法现象原因
* 计算矩阵乘法结果是逐元素乘积矩阵乘法用 @np.dot
A @ B 形状不匹配ValueError: matmul: Input operand 1 has a mismatch...A 的列数必须等于 B 的行数
对奇异矩阵 invLinAlgError: Singular matrix行列式为 0 的矩阵不可逆
lstsq 结果直接打印返回元组[0] 得到系数数组
eig 结果里有 +0.j 就以为错了特征值含虚部 0 的复数实矩阵特征值以复数形式返回,虚部 0 即实数
solve 后不验证手算错误没发现养成 A @ x 验证的习惯

章末练习

基础

  1. 计算 [[1, 0], [0, 1]] @ [[3, 4], [5, 6]],说明结果与什么相同。
  2. @ 计算两个 2×2 矩阵的乘积,并与 * 的结果对比。
  3. [[3, 1], [1, 2]] 的逆矩阵,并验证 A @ inv ≈ I

提高

  1. 解方程组 x + 2y = 83x + y = 9,给出 A、b、解,并用 A @ x 验证。
  2. 判断 [[2, 4], [1, 2]] 是否可逆(先算行列式),再尝试求逆,记录结果。

挑战

  1. lstsq 拟合抛物线 y = ax² + bx + c(提示:设计矩阵每行为 [x², x, 1]),对给定数据求系数并评估拟合质量。
  2. 三阶矩阵特征值:求 [[2, 1, 0], [1, 3, 1], [0, 1, 2]] 的特征值,验证 np.linalg.eig 的特征值之和等于矩阵的迹(对角线之和)。

章末自测

每题选择一个最佳答案。本书不附答案:完成后交由老师或 AI 老师批改讲解。

  1. 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. 报错
  2. 矩阵乘法应使用哪个运算符?
    • A. *
    • B. @
    • C. #
    • D. &
  3. np.array([[1, 2]]) @ np.array([[1], [2]]) 的结果是?
    • A. [[5]]
    • B. 5
    • C. [[1, 4]]
    • D. 报错
  4. 行列式为 0 的矩阵叫做?
    • A. 单位矩阵
    • B. 奇异矩阵
    • C. 对角矩阵
    • D. 对称矩阵
  5. 对奇异矩阵求逆会?
    • A. 返回全 0
    • B. 报 LinAlgError: Singular matrix
    • C. 返回单位矩阵
    • D. 返回 nan
  6. 解方程组 A x = b 应使用?
    • A. np.linalg.inv 直接左乘
    • B. np.linalg.solve(A, b)
    • C. np.dot(A, b)
    • D. A * b
  7. np.linalg.solve 之后验证结果的方法是?
    • A. A @ x 应等于 b
    • B. x @ A 应等于 b
    • C. A * x 应等于 b
    • D. 无法验证
  8. A @ v(A 是 m×n,v 是长度 n)的结果是?
    • A. m×n 矩阵
    • B. 长度 m 的向量
    • C. 标量
    • D. 报错
  9. np.linalg.det 返回的是?
    • A. 矩阵的秩
    • B. 矩阵的行列式
    • C. 矩阵的逆
    • D. 矩阵的特征值
  10. lstsq 的用途是?
    • A. 求矩阵的行列式
    • B. 找使残差平方和最小的拟合系数
    • C. 解任意非线性方程
    • D. 计算矩阵的特征值