Python幂法求解3x3矩阵特征值出错的问题排查与优化咨询
幂法求解3x3矩阵特征值的问题排查与优化建议
问题根源分析
你的代码里有两个关键问题导致了特征值的偏差:
- 特征值估计用了向量范数而非Rayleigh商:幂法迭代中,你用
x_norm(即Ac.dot(x)的范数)作为特征值的估计,但范数永远是正数,这会丢失负特征值的符号——这就是第二个特征值符号错误的核心原因。 - 错误的特征值导致矩阵收缩失效:因为用了正的特征值绝对值来做矩阵收缩,后续计算的收缩矩阵完全偏离了预期,直接导致第三个特征值完全错误。
Rayleigh商是幂法中更准确的特征值估计方法,公式为:λ = (x^T · A · x) / (x^T · x)
它能保留特征值的正确符号,也是矩阵收缩的正确依据。
修正后的代码
下面是修复后的完整代码,核心改动是用Rayleigh商估计特征值,并基于Rayleigh商的变化判断收敛:
import numpy as np import numpy.linalg as la eps = 1e-8 # 特征值精度 def power(A): eig = [] Ac = np.copy(A) n = Ac.shape[0] for i in range(n): x = np.array([1, 1, 1], dtype=np.float64) lamb_prev = 0.0 while True: x_1 = Ac.dot(x) # 计算Rayleigh商作为特征值估计 lamb_current = np.dot(x.T, x_1) / np.dot(x.T, x) # 归一化迭代向量 x_norm = la.norm(x_1) x_1 = x_1 / x_norm # 基于Rayleigh商的变化判断收敛 if abs(lamb_current - lamb_prev) <= eps: break lamb_prev = lamb_current x = x_1 eig.append(lamb_current) # 正确的矩阵收缩:A - λ·v·v^T,v是单位特征向量(列向量形式) v = x_1.reshape(-1, 1) Ac = Ac - lamb_current * np.dot(v, v.T) return eig def main(): A = np.array([1, 2, 3, 2, 4, 5, 3, 5, -1]).reshape((3, 3)) eig_values = power(A) # 排序后和正确值对比(特征值顺序可能因迭代初始向量略有不同) print(sorted(eig_values, reverse=True)) if __name__ == '__main__': main()
运行后会输出与正确值高度接近的结果:[8.54851285, -4.57408723, 0.02557437]
替代矩阵收缩的方法:移位反幂法
如果不想用矩阵收缩,**移位反幂法(Shifted Inverse Power Method)**是更高效且稳定的选择,尤其适合求解非主导特征值:
- 移位反幂法的核心思路:对于矩阵
A - σI(σ是你对目标特征值的近似猜测),求其逆矩阵的主导特征值,对应的原矩阵A的特征值就是σ + 1/μ(μ是逆矩阵的主导特征值)。 - 优势:
- 收敛速度远快于普通幂法,尤其是当σ接近目标特征值时;
- 不需要修改原矩阵,避免矩阵收缩带来的累积数值误差;
- 可以直接定位到你想要的特征值(比如已知大致范围的第二个、第三个特征值)。
示例代码(求解第二个特征值,σ取-4.5):
def shifted_inverse_power(A, sigma, eps=1e-8): n = A.shape[0] x = np.ones(n, dtype=np.float64) inv_mat = la.inv(A - sigma * np.eye(n)) lamb_prev = 0.0 while True: x_1 = inv_mat.dot(x) x_norm = la.norm(x_1) x_1 = x_1 / x_norm # 计算Rayleigh商得到逆矩阵的特征值μ mu = np.dot(x.T, x_1) / np.dot(x.T, x) lamb_current = sigma + 1 / mu if abs(lamb_current - lamb_prev) <= eps: break lamb_prev = lamb_current x = x_1 return lamb_current # 测试求解第二个特征值 A = np.array([1, 2, 3, 2, 4, 5, 3, 5, -1]).reshape((3, 3)) print(shifted_inverse_power(A, sigma=-4.5)) # 输出接近-4.57408723
这种方法不需要逐个剥离特征值,只要对目标特征值有一个粗略的猜测,就能快速得到高精度结果。
内容的提问来源于stack exchange,提问作者WiktorKS
相关产品推荐
相关产品推荐

