You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何SciPy的linalg.svd与linalg.lstsq返回的奇异值不匹配?

问题:lstsq与svd返回的奇异值不一致的原因

SciPy官方文档显示lstsq会返回观测矩阵X的奇异值,但使用scipy.linalg.svd直接计算时,得到的结果却和它不一致——二者趋势一致,但极值存在差异,这会影响条件数的估计,这是为什么?

复现代码

import numpy as np
from scipy.linalg import svd, lstsq
import matplotlib.pyplot as plt

# 生成观测矩阵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))

# 生成目标变量Y
Y = np.sin(X)

# 用lstsq获取奇异值
W, res, rank, s = lstsq(X, Y, cond=0) # cond=0 关闭奇异值截断
_, S, _ = svd(X.T @ X)

# 绘图对比
plt.semilogy(S, label='from svd')
plt.semilogy(s, label='from lstsq')
plt.legend()

奇异值对比图


原因分析

核心问题出在对svd的使用逻辑上:

  • lstsq返回的s是观测矩阵X本身的奇异值,即对X直接做SVD分解得到的结果。
  • 原代码中svd(X.T @ X)计算的是X的Gram矩阵(XᵀX)的奇异值,而Gram矩阵的奇异值实际上是X的奇异值的平方,这就导致了两者数值上的差异。

另外补充:即使修正为直接对X做SVD,由于lstsq内部调用的LAPACK接口(如_gelsd或_gelsy)与直接调用svd的接口(如_gesvd)存在细微的数值计算策略差异,可能会有极微小的浮点精度误差,但整体数值会完全对齐,不会影响条件数的估计。

修正后的代码

将svd(X.T @ X)改为直接对X做SVD并只获取奇异值:

import numpy as np
from scipy.linalg import svd, lstsq
import matplotlib.pyplot as plt

# 生成观测矩阵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))

# 生成目标变量Y
Y = np.sin(X)

# 用lstsq获取X的奇异值
W, res, rank, s_lstsq = lstsq(X, Y, cond=0)
# 直接对X做SVD获取奇异值
s_svd = svd(X, compute_uv=False)

# 绘图对比
plt.semilogy(s_svd, label='来自svd')
plt.semilogy(s_lstsq, label='来自lstsq')
plt.legend()
plt.show()

修正后,两者的奇异值曲线会完全重合(或仅有可忽略的浮点精度差异),条件数的计算结果也会一致。


内容的提问来源于stack exchange,提问作者arash

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 21:16:18