为什么 SciPy 的 `linalg.svd` 和 `linalg.lstsq` 的符号值不匹配?

问题描述 投票:0回答:1

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()

numpy scipy linear-regression svd
1个回答
0
投票

您一方面计算 X 的奇异值,另一方面计算 XᵀX 的奇异值。所以,结果不一样。

更准确地说,第二个结果是第一个结果的平方。因此是对数尺度上的乘法因子。

如果你想确信这一点,只需绘制 svd 的平方根即可

_, S, _ = svd(X.T@X)
plt.semilogy(np.sqrt(S), label='from svd')
plt.semilogy(s, label='from lstsq')

或者,与正确的计算进行比较

_, S, _ = svd(X)
plt.semilogy(S, label='from svd')
plt.semilogy(s, label='from lstsq')

(相同结果)

在您的代码中,

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 奇异值的平方。这正是您的图表所显示的。

© www.soinside.com 2019 - 2024. All rights reserved.