线性代数方阵求逆运算实例演示及常见计算错误纠正指南
逆矩阵到底是什么?
想象你手里有一个算式:A × X = B,你想求出 X。在普通算术里,我们两边同时除以 A 就行。但矩阵没有”除法”这个概念,所以我们发明了”逆矩阵”——找到一个矩阵 A⁻¹,使得 A × A⁻¹ = I(单位矩阵),然后两边左乘 A⁻¹,就能得到 X = A⁻¹ × B。
是不是有点抽象?我们用一个小例子感受下。
2×2 矩阵的求逆:最基础的入门
对于二阶方阵:
A = [a b]
[c d]
它的逆矩阵有一个简洁的公式:
A⁻¹ = 1/(ad - bc) × [d -b]
[-c a]
这里 ad - bc 就是行列式,通常记作 det(A) 或 |A|。
⚠️ 关键前提:行列式不为零,矩阵才可逆。行列式为零的矩阵叫”奇异矩阵”,没有逆。
实例演算
设矩阵 A =
[ 4 7 ]
[ 2 6 ]
第一步:计算行列式
det(A) = 4×6 - 7×2 = 24 - 14 = 10
行列式是 10,不等于零,说明 A 可逆 ✅
第二步:套用公式
A⁻¹ = 1/10 × [ 6 -7 ]
[-2 4 ]
= [ 6/10 -7/10 ]
[-2/10 4/10 ]
= [ 0.6 -0.7 ]
[-0.2 0.4 ]
第三步:验证
A × A⁻¹ = [4 7] × [0.6 -0.7]
[2 6] [-0.2 0.4]
第一行第一列:4×0.6 + 7×(-0.2) = 2.4 - 1.4 = 1 ✅
第一行第二列:4×(-0.7) + 7×0.4 = -2.8 + 2.8 = 0 ✅
第二行第一列:2×0.6 + 6×(-0.2) = 1.2 - 1.2 = 0 ✅
第二行第二列:2×(-0.7) + 6×0.4 = -1.4 + 2.4 = 1 ✅
结果 = [1 0] = I ✔️
[0 1]
3×3 矩阵求逆:初等行变换法(高斯-约旦消元)
3×3 及以上矩阵,用公式法(伴随矩阵)会越来越痛苦。最实用、最稳定的方法是初等行变换,也叫高斯-约旦消元法。
核心思想
把待求逆的矩阵 A 和单位矩阵 I 并排放在一起,组成增广矩阵 [A | I]。然后对左边部分做行变换,把它变成单位矩阵,右边部分自然就成了 A⁻¹。
[A | I] ────行变换───→ [I | A⁻¹]
实例演算
设矩阵 A =
[ 1 2 3 ]
[ 0 1 4 ]
[ 5 6 0 ]
第一步:构造增广矩阵
[ 1 2 3 | 1 0 0 ]
[ 0 1 4 | 0 1 0 ]
[ 5 6 0 | 0 0 1 ]
第二步:把第3行的第1列消成0
第3行 = 第3行 - 5×第1行:
R3 = R3 - 5×R1
[ 1 2 3 | 1 0 0 ]
[ 0 1 4 | 0 1 0 ]
[ 0 -4 -15 | -5 0 1 ]
第三步:把第3行的第2列消成0
第3行 = 第3行 + 4×第2行:
R3 = R3 + 4×R2
[ 1 2 3 | 1 0 0 ]
[ 0 1 4 | 0 1 0 ]
[ 0 0 1 | -5 4 1 ]
第四步:把第2行的第3列消成0
第2行 = 第2行 - 4×第3行:
R2 = R2 - 4×R3
[ 1 2 3 | 1 0 0 ]
[ 0 1 0 | 20 -15 -4 ]
[ 0 0 1 | -5 4 1 ]
第五步:把第1行的第3列消成0
第1行 = 第1行 - 3×第3行:
R1 = R1 - 3×R3
[ 1 2 0 | 16 -12 -3 ]
[ 0 1 0 | 20 -15 -4 ]
[ 0 0 1 | -5 4 1 ]
第六步:把第1行的第2列消成0
第1行 = 第1行 - 2×第2行:
R1 = R1 - 2×R2
[ 1 0 0 | -24 18 5 ]
[ 0 1 0 | 20 -15 -4 ]
[ 0 0 1 | -5 4 1 ]
结果:
A⁻¹ = [ -24 18 5 ]
[ 20 -15 -4 ]
[ -5 4 1 ]
验证:
A × A⁻¹ 的第1行第1列 = 1×(-24) + 2×20 + 3×(-5) = -24 + 40 - 15 = 1 ✅
A × A⁻¹ 的第1行第2列 = 1×18 + 2×(-15) + 3×4 = 18 - 30 + 12 = 0 ✅
A × A⁻¹ 的第2行第2列 = 0×18 + 1×(-15) + 4×4 = -15 + 16 = 1 ✅
...(类似验证其余元素)
Python 代码实现:从原理到实战
方法一:用 NumPy(生产环境首选)
import numpy as np
# 定义矩阵
A = np.array([[1, 2, 3],
[0, 1, 4],
[5, 6, 0]], dtype=float)
# 计算逆矩阵
A_inv = np.linalg.inv(A)
print("原矩阵 A:")
print(A)
print("\n逆矩阵 A⁻¹:")
print(A_inv)
# 验证
identity = np.dot(A, A_inv)
print("\n验证 A × A⁻¹:")
print(identity)
输出:
原矩阵 A:
[[1 2 3]
[0 1 4]
[5 6 0]]
逆矩阵 A⁻¹:
[[-24. 18. 5.]
[ 20. -15. -4.]
[ -5. 4. 1.]]
验证 A × A⁻¹:
[[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]]
方法二:手动实现高斯-约旦消元(理解原理用)
def manual_inverse(matrix):
"""手动实现高斯-约旦消元求逆矩阵"""
n = len(matrix)
# 构造增广矩阵 [A | I]
aug = []
for i in range(n):
row = matrix[i][:] + [1.0 if i == j else 0.0 for j in range(n)]
aug.append(row)
# 打印增广矩阵初始状态
print("初始增广矩阵 [A | I]:")
for row in aug:
print(["{:8.2f}".format(x) for x in row])
print()
# 对每一列进行消元
for col in range(n):
# 1. 选主元(当前列绝对值最大的行,减少舍入误差)
max_row = col
for row in range(col + 1, n):
if abs(aug[row][col]) > abs(aug[max_row][col]):
max_row = row
# 交换行
aug[col], aug[max_row] = aug[max_row], aug[col]
# 打印交换后的状态
print(f"--- 处理第 {col} 列,交换后 ---")
for row in aug:
print(["{:8.2f}".format(x) for x in row])
print()
# 2. 用主元行将当前列的所有其他行消为0
pivot = aug[col][col]
if abs(pivot) < 1e-12:
raise ValueError("矩阵奇异,无法求逆!行列式为零。")
# 主元行归一化
for j in range(2 * n):
aug[col][j] /= pivot
# 其他行消元
for row in range(n):
if row != col:
factor = aug[row][col]
for j in range(2 * n):
aug[row][j] -= factor * aug[col][j]
# 打印消元后的状态
print(f"--- 第 {col} 列消元完成 ---")
for row in aug:
print(["{:8.2f}".format(x) for x in row])
print()
# 提取逆矩阵(增广矩阵右半部分)
inverse = []
for i in range(n):
inverse.append(aug[i][n:])
return inverse
# 测试
A = [[1, 2, 3],
[0, 1, 4],
[5, 6, 0]]
result = manual_inverse(A)
print("手动计算的逆矩阵:")
for row in result:
print(["{:8.2f}".format(x) for x in row])
运行后会清晰看到每一步的行变换过程,非常有助于理解算法细节。
方法三:用伴随矩阵法(适合小矩阵教学)
import numpy as np
def cofactor_matrix(matrix):
"""计算余子式矩阵"""
n = len(matrix)
cofactors = np.zeros((n, n))
for i in range(n):
for j in range(n):
# 去掉第i行第j列,得到子矩阵
sub_matrix = np.delete(np.delete(matrix, i, axis=0), j, axis=1)
# 代数余子式 = (-1)^(i+j) × 子矩阵行列式
cofactors[i][j] = ((-1) ** (i + j)) * np.linalg.det(sub_matrix)
return cofactors
def inverse_by_adjugate(matrix):
"""伴随矩阵法求逆"""
matrix = np.array(matrix, dtype=float)
n = len(matrix)
# 1. 计算行列式
det = np.linalg.det(matrix)
print(f"行列式 det(A) = {det:.6f}")
if abs(det) < 1e-12:
print("❌ 行列式为零,矩阵不可逆!")
return None
# 2. 计算伴随矩阵 = 余子式矩阵的转置
cofactors = cofactor_matrix(matrix)
adjugate = cofactors.T
print("\n余子式矩阵:")
print(cofactors)
print("\n伴随矩阵(余子式矩阵的转置):")
print(adjugate)
# 3. 逆矩阵 = 伴随矩阵 / 行列式
inverse = adjugate / det
return inverse
# 测试
A = np.array([[4, 7],
[2, 6]], dtype=float)
print("2×2 矩阵示例:")
inv_A = inverse_by_adjugate(A)
print("\n逆矩阵:")
print(inv_A)
print("\n验证 A × A⁻¹:")
print(np.dot(A, inv_A))
常见计算错误全扫描
这一块是我觉得最有价值的部分。下面这些坑,几乎每个学过线性代数的人都踩过。
错误一:忘记检查行列式是否为零
import numpy as np
# 一个奇异矩阵的例子
singular_A = np.array([[1, 2],
[2, 4]], dtype=float) # 第二行是第一行的2倍
print("行列式:", np.linalg.det(singular_A)) # 输出接近 0
try:
inv = np.linalg.inv(singular_A)
print(inv)
except np.linalg.LinAlgError as e:
print(f"❌ 报错:{e}") # LinAlgError: Singular matrix
规律:两行(或两列)成比例、某行全为零、或某列可由其他列线性表示 → 行列式为零 → 不可逆。
错误二:转置和求逆搞混
很多人混淆 (A⁻¹)ᵀ 和 (Aᵀ)⁻¹。实际上它们相等:
(Aᵀ)⁻¹ = (A⁻¹)ᵀ
但这个等式在计算时容易出错,尤其是手写推导。看代码:
import numpy as np
A = np.array([[1, 2],
[3, 5]], dtype=float)
A_inv = np.linalg.inv(A)
A_T = A.T
# 方法1:先转置再求逆
method1 = np.linalg.inv(A_T)
# 方法2:先求逆再转置
method2 = A_inv.T
print("先转置再求逆:\n", method1)
print("先求逆再转置:\n", method2)
print("两者相等?", np.allclose(method1, method2)) # True
虽然结果相等,但数值上可能有微小差异(浮点误差)。在编程中建议统一用一种方式。
错误三:行列式计算错误(符号问题)
用余子式展开时,代数余子式的符号 (-1)^(i+j) 经常被漏掉或算错。
# 3×3 矩阵的行列式展开
A = np.array([[2, -1, 3],
[4, 0, 1],
[1, 2, 5]])
# 方法1:直接调用(推荐)
det1 = np.linalg.det(A)
print(f"直接计算行列式: {det1:.2f}")
# 方法2:按第一行展开(手动验证)
# det = a11·C11 + a12·C12 + a13·C13
# Cij = (-1)^(i+j) × Mij(Mij是余子式)
M11 = np.linalg.det(np.array([[0, 1], [2, 5]])) # = 0×5 - 1×2 = -2
M12 = np.linalg.det(np.array([[4, 1], [1, 5]])) # = 4×5 - 1×1 = 19
M13 = np.linalg.det(np.array([[4, 0], [1, 2]])) # = 4×2 - 0×1 = 8
det2 = (2 * M11 * 1) + (-1 * M12 * 1) + (3 * M13 * 1)
# = 2×(-2) - 1×19 + 3×8
# = -4 - 19 + 24
# = 1
print(f"手动展开行列式: {det2:.2f}")
print(f"两者一致?{abs(det1 - det2) < 1e-10}")
记忆口诀:余子式矩阵的符号像棋盘,+ - +、- + -、+ - +,行标列标之和为奇数时取负。
错误四:把求逆当成求转置
有些初学者会直接把矩阵转置当作逆矩阵。让我们看看错误有多大:
import numpy as np
A = np.array([[1, 2],
[3, 4]], dtype=float)
A_inv = np.linalg.inv(A)
A_T = A.T
print("原矩阵 A:")
print(A)
print("\n正确的逆矩阵 A⁻¹:")
print(A_inv)
print("\n错误的转置 Aᵀ:")
print(A_T)
print("\n验证 A × A⁻¹(应该≈单位矩阵):")
print(np.dot(A, A_inv))
print("\n验证 A × Aᵀ(这是错的!):")
print(np.dot(A, A_T))
输出会清楚地告诉你:A × Aᵀ 根本得不到单位矩阵。
错误五:行变换时顺序搞错
在高斯消元过程中,先处理列,再处理行,或者同一列没消完就换下一列,都会导致结果错误。
正确顺序(高斯-约旦):
第1列:用第1行把第2、3行的第1列消成0 → 第1行归一化
第2列:用第2行把第1、3行的第2列消成0 → 第2行归一化
第3列:用第3行把第1、2行的第3列消成0 → 第3行归一化
注意:处理第 k 列时,所有行都要参与消元(不仅是下方行,上方行也要消),因为我们在构造的是单位矩阵。
错误六:把矩阵乘法当成逐元素乘法
这是编程新手最常犯的错误。Python 中 * 运算符对 NumPy 数组执行的是逐元素相乘,不是矩阵乘法!
import numpy as np
A = np.array([[1, 2],
[3, 4]], dtype=float)
A_inv = np.linalg.inv(A)
# ❌ 错误:逐元素相乘
wrong = A * A_inv
print("逐元素相乘(错误):")
print(wrong)
# ✅ 正确:矩阵乘法
correct = np.dot(A, A_inv)
print("\n矩阵乘法(正确):")
print(correct)
# 也可以用 @ 运算符(Python 3.5+)
correct2 = A @ A_inv
print("\n用 @ 运算符:")
print(correct2)
错误七:忽视数值稳定性——条件数过大
即使行列式不为零,矩阵也可能因为接近奇异而导致求逆结果极不准确。
import numpy as np
# 一个条件数很大的矩阵(接近奇异)
A = np.array([[1, 1],
[1, 1.0001]], dtype=float)
print(f"行列式: {np.linalg.det(A):.8f}")
print(f"条件数: {np.linalg.cond(A):.2e}")
A_inv = np.linalg.inv(A)
print("\n逆矩阵:")
print(A_inv)
# 验证
print("\n验证 A × A⁻¹:")
print(np.dot(A, A_inv))
条件数 cond(A) = ||A|| × ||A⁻¹|| 衡量了矩阵对数值误差的敏感程度。条件数越大,求逆结果越不可靠。一般建议:
- 条件数 < 10⁶:结果可信
- 条件数 > 10⁸:结果可能严重失真
错误八:忘记逆矩阵的唯一性
有些同学会认为一个矩阵有多个逆矩阵。实际上:
如果矩阵 A 可逆,则它的逆矩阵唯一。
证明思路:假设 B 和 C 都是 A 的逆,则 B = B×I = B×(A×C) = (B×A)×C = I×C = C,所以 B = C。
实际应用场景:用逆矩阵解线性方程组
逆矩阵最大的用处之一就是解方程组。设方程组:
2x + 3y = 8
4x + 5y = 14
写成矩阵形式:AX = B
A = [2 3] X = [x] B = [8]
[4 5] [y] [14]
解法:X = A⁻¹ × B
import numpy as np
A = np.array([[2, 3],
[4, 5]], dtype=float)
B = np.array([8, 14], dtype=float)
# 方法1:用逆矩阵(理论正确,实际不推荐直接用于求解)
A_inv = np.linalg.inv(A)
X1 = A_inv @ B
print("用逆矩阵求解:", X1)
# 方法2:直接用 solve(数值上更稳定,推荐!)
X2 = np.linalg.solve(A, B)
print("用 solve 求解:", X2)
# 验证
print("\n代入原方程组验证:")
print(f"2×{X2[0]} + 3×{X2[1]} = {2*X2[0] + 3*X2[1]:.2f} (应等于 8)")
print(f"4×{X2[0]} + 5×{X2[1]} = {4*X2[0] + 5*X2[1]:.2f} (应等于 14)")
重要提示:在实际工程中,解线性方程组不要用 inv(A) @ B,而应该用 np.linalg.solve(A, B)。前者多算了一次求逆,数值上也更不稳定。求逆只在真正需要逆矩阵本身时才有意义。
逆矩阵的重要性质(速查表)
| 性质 | 公式 | 备注 |
|---|---|---|
| 互逆性 | (A⁻¹)⁻¹ = A |
求逆两次回到原点 |
| 转置与求逆可交换 | (Aᵀ)⁻¹ = (A⁻¹)ᵀ |
先转置再求逆 = 先求逆再转置 |
| 乘积的逆 | (AB)⁻¹ = B⁻¹A⁻¹ |
顺序要反转 |
| 幂的逆 | (Aⁿ)⁻¹ = (A⁻¹)ⁿ |
n 为整数 |
| 行列式关系 | det(A⁻¹) = 1/det(A) |
行列式不为零才可逆 |
| 标量乘法 | (kA)⁻¹ = (1/k)A⁻¹ |
k ≠ 0 |
其中 (AB)⁻¹ = B⁻¹A⁻¹ 是最容易记反的,记住:脱衣服时先脱最外层,穿衣服时最后穿最外层;求逆时顺序要反转。
总结
求逆矩阵这件事,表面看是套公式,但背后涉及不少细节:
- 先判断:行列式是否为零?条件数是否过大?
- 选方法:2×2 用公式最快,3×3 以上用高斯-约旦或编程求解。
- 防错误:别把转置当逆矩阵、别把逐元素乘法当矩阵乘法、注意行变换顺序。
- 懂取舍:实际求解方程组用
solve而非inv。
掌握这些,你基本就能在考试和工程中都游刃有余了。
