SciPy 的文档说lstsq
返回观察矩阵的奇异值。但是,当我直接使用奇异值分解(来自 SciPy 的相同实现)来计算它们时scipy.linalg.svd
,我得到了一组不同的值。
两者的趋势当然是相同的。但似乎它们的最小值和最大值是不同的。这尤其重要,因为它改变了条件数估计。为什么它们不同?
这是复制此内容的代码:
import numpy as np
from scipy.linalg import svd, lstsq
import matplotlib.pyplot as plt
# Let's generate some interesting X
X = np.arange(100*50, dtype=float).reshape(100,50)
X = np.sin(X) + np.tan(X) + np.cos(X)
X += np.random.normal(0,3, size=(100,50))
# And some function which we want to fit
# (for now it does't matter)
Y = np.sin(X)
# Let's compute the signular values of the observation matrix X
W, res, rank, s = lstsq(X, Y, cond=0) # cond=0 to deactivate sing-val truncation
_, S, _ = svd(X.T @ X)
# They should match exactly
plt.semilogy(S, label='from svd')
plt.semilogy(s, label='from lstsq')
plt.legend()
您一方面计算 X 的奇异值,另一方面计算 XᵀX 的奇异值。所以,结果不一样。
更准确地说,第二个结果是第一个结果的平方。因此是对数尺度上的乘法因子。
如果你想确信这一点,只需绘制 svd 的平方根
⇒
或者,与正确的计算进行比较
(相同的结果)
在您的代码中,
s
是 的奇异值X
, 和S
的奇异值X.T@X
。如此不同的事情。X*X
但之所以一个是另一个的平方,是因为奇异值的定义:奇异值是(这里 =XᵀX
因为这些都是实值)的特征值的平方根。所以,这XᵀX
部分已经由 svd 完成了。如果 λ 是 的特征值
XᵀX
,即如果 ∃u≠0,XᵀXu = λu,则 (XᵀX)ᵀ(XᵀX) = (XᵀX)(XᵀX)u = XᵀX λu = λ²u。所以 λ² 是 (XᵀX)ᵀ(XᵀX) 的特征值。因此,如果
s
是 X 的奇异值,即如果 s² 是 XᵀX 的特征值,则 s⁴ 是 (XᵀX)ᵀ(XᵀX) 的特征值,则 s² 是 XᵀX 的奇异值。所以,这里没什么奇怪的。XᵀX 的奇异值是 X 奇异值的平方。这正是您的图表所显示的。