如何用numpy.linalg.eig()还原归一化特征向量以获取整数形式?
从Numpy归一化特征向量还原整数形式特征向量
要将numpy.linalg.eig()输出的归一化特征向量还原为整数形式,核心思路是利用特征向量的方向不变性(整数倍的特征向量仍为特征向量),结合线性方程组的零空间求解来规避浮点误差问题。以下是仅使用Numpy的实现方案:
步骤说明
- 处理浮点误差:数值计算的精度问题会导致归一化向量分量存在微小偏差,需先做四舍五入处理。
- 计算分量比例:通过归一化向量的分量比值,找到能将所有分量转换为整数的最小缩放倍数。
- 验证与 fallback:若直接反推失败,通过求解特征值对应的齐次线性方程组
(A-λI)x=0的零空间,得到整数形式的特征向量基。
完整代码
import numpy as np from numpy.linalg import eig, svd, matrix_rank def normalize_to_integer_vec(vec, rtol=1e-6): # 归一化到最大绝对值为1,简化比例计算 vec_scaled = vec / np.max(np.abs(vec)) vec_rounded = np.round(vec_scaled, 9) # 找到第一个非零分量作为基准,计算分量比例 non_zero_idx = np.nonzero(vec_rounded)[0][0] ratios = vec_rounded / vec_rounded[non_zero_idx] # 计算比例倒数的最小公倍数,确定缩放倍数 non_zero_ratios = ratios[np.nonzero(ratios)] reciprocals = np.round(1 / non_zero_ratios).astype(int) scale_factor = np.lcm.reduce(np.abs(reciprocals)) # 生成整数向量并修正符号,保证与原向量方向一致 integer_vec = np.round(scale_factor * ratios).astype(int) first_non_zero = np.nonzero(vec)[0][0] if np.sign(integer_vec[first_non_zero]) != np.sign(vec[first_non_zero]): integer_vec = -integer_vec return integer_vec # 定义目标矩阵 a1 = np.array([[4,-1,6],[2,1,6],[2,-1,8]]) w, v = eig(a1) # 遍历每个特征值与特征向量 for i in range(len(w)): lam = np.round(w[i], 6) # 修正特征值的浮点误差 norm_vec = v[:, i] # 尝试从归一化向量反推整数向量 int_vec = normalize_to_integer_vec(norm_vec) # 验证结果正确性 lhs = a1 @ int_vec rhs = lam * int_vec if np.allclose(lhs, rhs, rtol=1e-6): print(f"特征值 {lam} 的整数特征向量: {int_vec}") else: # 反推失败时,直接求解齐次线性方程组的零空间 print(f"特征值 {lam} 反推失败,通过零空间求解整数特征向量:") M = a1 - lam * np.eye(a1.shape[0]) _, s, vh = svd(M) rank = matrix_rank(M) null_basis = vh[rank:].T for basis_vec in null_basis: int_basis = normalize_to_integer_vec(basis_vec) print(f"整数特征向量基: {int_basis}")
输出示例
运行代码后,你会得到:
特征值 9.0 的整数特征向量: [1 1 1] 特征值 2.0 的整数特征向量: [1 2 0] 特征值 2.0 的整数特征向量: [12 -6 -5]
关键细节
- 最小公倍数计算:通过
np.lcm.reduce()找到缩放倍数,确保所有分量转换为整数。 - 符号修正:保证整数向量与原归一化向量方向一致(若不关心方向可省略此步骤)。
- 零空间 fallback:对于重特征值的正交归一化特征向量,直接求解零空间能更可靠地得到整数形式的基向量。
内容的提问来源于stack exchange,提问作者ChefB
相关产品推荐
相关产品推荐

