【发布时间】:2014-03-17 09:09:17
【问题描述】:
在 numpy 中计算矩阵求逆(求解线性系统)时,我的不准确度似乎高得无法接受。
- 这是正常水平的不准确吗?
- 如何提高此计算的准确性?
- 另外,有没有办法在 numpy 或 scipy 中更有效地解决这个系统(
scipy.linalg.cho_solve似乎很有希望,但没有做我想要的)?
在下面的代码中,cholM 是一个 128 x 128 矩阵。矩阵数据太大,无法包含在此处,但位于 pastebin:cholM.txt。
此外,原始向量ovec 是随机选择的,因此对于不同的ovec,其准确度会有所不同,但在大多数情况下,误差似乎仍然高得无法接受。
编辑使用奇异值分解求解系统产生的误差明显低于其他方法。
import numpy.random as rnd
import numpy.linalg as lin
import numpy as np
cholM=np.loadtxt('cholM.txt')
dims=len(cholM)
print 'Dimensions',dims
ovec=rnd.normal(size=dims)
rvec=np.dot(cholM.T,ovec)
invCholM=lin.inv(cholM.T)
svec=np.dot(invCholM,rvec)
svec1=lin.solve(cholM.T,rvec)
def back_substitute(M,v):
r=np.zeros(len(v))
k=len(v)-1
r[k]=v[k]/M[k,k]
for k in xrange(len(v)-2,-1,-1):
r[k]=(v[k]-np.dot(M[k,k+1:],r[k+1:]))/M[k,k]
return r
svec2=back_substitute(cholM.T,rvec)
u,s,v=lin.svd(cholM)
svec3=np.dot(u,np.dot(np.diag(1./s),np.dot(v,rvec)))
for k in xrange(dims):
print '%20.3f%20.3f%20.3f%20.3f'%(ovec[k]-svec[k],ovec[k]-svec1[k],ovec[k]-svec2[k],ovec[k]-svec3[k])
assert np.all( np.abs(ovec-svec)<1e-5 )
assert np.all( np.abs(ovec-svec1)<1e-5 )
【问题讨论】:
-
这通常表明您的矩阵是病态的。对于您提供的下三角矩阵,最大奇异值与最小奇异值(条件数)的比率似乎约为 10 ^ 16。这绝对是个问题。
-
为什么条件数在这里很重要?我正在取逆,所以通常情况下,如果矩阵接近奇异,我会担心。
cholM矩阵是三角形的,所以对角线上非常小的值肯定会影响解,但这种情况不会发生。 -
您可以尝试将 cholM 和 invCholM 相乘,然后减去单位矩阵以说服自己条件数是否重要
-
条件号by definition 衡量您可以获得的最大误差。因此,它无疑将忠实地估计朴素反向替换的准确性。您提供的矩阵的条件数是 ~1e16,而不是 44.6。特征值通常不会给你条件数,除了正态矩阵(cholM 显然不是)。
-
这里似乎有误会。条件数不会影响数学世界中的解决方案;它们确实影响了计算机科学领域的解决方案。条件编号 1e16 绝对是个坏消息。确保您对初学者使用双精度。如果这没有帮助;求解同一系统的不同方法对数值误差的敏感性可能大不相同。我看到的这种反向替代也完全属于“不要在条件不好的情况下尝试这个”阵营。
标签: numpy scipy linear-algebra