如何避免使用NumPy进行线性代数运算时出现不精确结果?
矩阵代数运算的浮点精度问题与精确计算方案
问题详情
执行以下矩阵运算代码:
import numpy as np from numpy import linalg A = np.array([[1,2],[1,-1],[1,1]]) b = np.array([[1],[-1],[5]]) r = linalg.inv(A.transpose()@A)@A.transpose()@b print(r)
输出结果为:
[[1.] [1.]]
手动计算的预期结果是严格整数形式的[[1],[1]],但使用该浮点结果进行后续运算(如A@r)时,得到:
[[3.00000000e+00] [3.33066907e-16] [2.00000000e+00]]
而非预期的[[3],[0],[2]],需要找到避免浮点精度误差的方法,比如用分数运算替代浮点求逆。
解决方案
1. 利用fractions模块实现精确有理数运算
使用Python标准库的Fraction类型存储矩阵元素,所有运算都会以精确分数形式进行,彻底避免浮点误差:
from fractions import Fraction import numpy as np # 初始化分数类型的矩阵 A = np.array([[Fraction(1), Fraction(2)], [Fraction(1), Fraction(-1)], [Fraction(1), Fraction(1)]]) b = np.array([[Fraction(1)], [Fraction(-1)], [Fraction(5)]]) # 计算正规方程的精确解 A_T = A.transpose() A_T_A = A_T @ A # 手动计算2x2矩阵的逆(小矩阵可直接通过行列式精确求解) det = A_T_A[0,0] * A_T_A[1,1] - A_T_A[0,1] * A_T_A[1,0] A_T_A_inv = np.array([[A_T_A[1,1]/det, -A_T_A[0,1]/det], [-A_T_A[1,0]/det, A_T_A[0,0]/det]]) r = A_T_A_inv @ A_T @ b print(r)
运行后输出精确的整数结果:
[[1] [1]]
后续执行A@r会得到完全符合预期的[[3], [0], [2]]。
2. 结合numpy.linalg.lstsq与分数类型
使用numpy的最小二乘函数直接求解,同时指定元素类型为object存储分数,实现精确计算:
import numpy as np from fractions import Fraction # 初始化矩阵并转换为分数类型 A = np.array([[1,2],[1,-1],[1,1]], dtype=object) b = np.array([[1],[-1],[5]], dtype=object) A = np.vectorize(Fraction)(A) b = np.vectorize(Fraction)(b) # 最小二乘求解 r, _, _, _ = np.linalg.lstsq(A, b, rcond=None) print(r)
该方法同样能输出精确的整数结果,避免浮点精度问题。
3. 对浮点结果进行舍入处理
如果不需要严格的分数精度,仅需后续运算结果符合预期,可以对浮点解进行合理舍入:
import numpy as np from numpy import linalg A = np.array([[1,2],[1,-1],[1,1]]) b = np.array([[1],[-1],[5]]) r = linalg.inv(A.transpose()@A)@A.transpose()@b # 因预期结果为整数,直接取整 r = np.round(r).astype(int) print(r) # 后续计算验证 print(A@r)
运行后输出:
[[1] [1]] [[3] [0] [2]]
内容的提问来源于stack exchange,提问作者shintuku
相关产品推荐
相关产品推荐

