我正在尝试使用Cholesky分解,但是这个功能实际上并没有在scipy中实现,或者有些东西我不理解。我发布在这里是为了后者。这是我正在做的一个简化示例:
import numpy
import scipy.linalg
numpy.random.seed(0)
X = numpy.random.normal(size=(10,4))
V = numpy.dot(X.transpose(),X)
R = V.copy()
scipy.linalg.cholesky(R,False,overwrite_a=True)
print V
print R
我认为应该发生的是R被上三角矩阵覆盖。但是,当我运行此代码时,我的V和R出来的相同(cholesky不会覆盖R)。我误解了overwrite_a的目的,还是犯了其他错误?如果这只是scipy中的一个错误,是否有一种解决方法或其他方式我可以在Python中进行Cholesky分解?
答案 0 :(得分:4)
使用
再试一次>>> scipy.__version__
'0.11.0'
>>> np.__version__
'1.6.2'
它完美无缺:
X = np.random.normal(size=(10,4))
V = np.dot(X.transpose(),X)
print V
R = V.copy()
print R
C = scipy.linalg.cholesky(R,False,overwrite_a=True)
print V
print R
输出是:
[[ 11.22274635 5.10611692 0.70263037 3.14603088] # V before
[ 5.10611692 8.94518939 -3.17865941 1.64689675]
[ 0.70263037 -3.17865941 7.35385131 -2.23948391]
[ 3.14603088 1.64689675 -2.23948391 8.25112653]]
[[ 11.22274635 5.10611692 0.70263037 3.14603088] # R before
[ 5.10611692 8.94518939 -3.17865941 1.64689675]
[ 0.70263037 -3.17865941 7.35385131 -2.23948391]
[ 3.14603088 1.64689675 -2.23948391 8.25112653]]
[[ 11.22274635 5.10611692 0.70263037 3.14603088] # V after
[ 5.10611692 8.94518939 -3.17865941 1.64689675]
[ 0.70263037 -3.17865941 7.35385131 -2.23948391]
[ 3.14603088 1.64689675 -2.23948391 8.25112653]]
[[ 3.35003677 1.52419728 0.20973811 0.93910339] # R after
[ 0. 2.57332704 -1.35946252 0.08375069]
[ 0. 0. 2.33703292 -0.99382158]
[ 0. 0. 0. 2.52478036]]
答案 1 :(得分:2)
如果您足够勇敢,可以避免scipy
并进行linalg.lapack_lite.dpotrf
的低级别电话
import numpy as np
# prepare test data
A = np.random.normal(size=(10,10))
A = np.dot(A,A.T)
L = np.tril(A)
# actual in-place cholesky
assert L.dtype is np.dtype(np.float64)
assert L.flags['C_CONTIGUOUS']
n, m = L.shape
assert n == m
result = np.linalg.lapack_lite.dpotrf('U', n, L, n, 0)
assert result['info'] is 0
# check if L is the desired L cholesky factor
assert np.allclose(np.dot(L,L.T), A)
assert np.allclose(L, np.linalg.cholesky(A))
你必须了解lapack的DPOTRF,fortran调用约定,内存布局。退出时请不要忘记检查result['info'] == 0
。尽管如此,你只看到它只是一行代码,并且通过丢弃linalg.cholesky
完成的所有健全性检查和复制,这也可能更有效。
答案 2 :(得分:1)
为了完整起见,以下基于Warren评论的代码解决了这个问题:
import numpy
import scipy.linalg
numpy.random.seed(0)
X = numpy.random.normal(size=(10,4))
V = numpy.dot(X.transpose(),X)
R = V.copy('F')
print V.flags['C_CONTIGUOUS']
print R.flags['F_CONTIGUOUS']
scipy.linalg.cholesky(R,False,overwrite_a=True)
print V
print R
我所做的就是将R的基础存储格式从C顺序更改为Fortran顺序,这会导致overwrite_a
按预期运行。
如果您的矩阵是真正有价值的,那么只需将转置传递给cholesky即可完成此操作而无需复制。如果你的矩阵是复值的话,我认为转置修正不会起作用,因为复杂的厄米特矩阵的转置通常不等于它的共轭转置。但是,如果您确保您的矩阵首先使用fortran顺序(R.flags['F_CONTIGUOUS'] == True
),那么您应该没有问题。但是,请参阅Setting the *default* data order (C vs. Fortran) in Numpy了解该策略的难度。