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

基于SVD的线性方程最小二乘求解问题排查与原理咨询

基于SVD的最小二乘求解问题与解答

问题代码与输出

import numpy as np
from scipy import linalg

np.random.seed(123)
v = np.random.rand(4)
A = v[:,None] * v[None,:]
b = np.random.randn(4)

x = linalg.inv(A.T.dot(A)).dot(A.T).dot(b) # 通常不推荐,因正规方程存在数值不稳定性
l2_0= linalg.norm(A.dot(x) - b)
print("manually: ", l2_0)

x = linalg.lstsq(A, b)[0]
l2_1= linalg.norm(A.dot(x) - b)
print("scipy.linalg.lstsq: ", l2_1)

# 比较两种计算的2-范数
print(np.allclose(l2_0, l2_1, rtol=1.3e-1))

def direct_ls_svd(x,y):
  # 添加全1列(偏置项)
  x = np.column_stack([np.ones(x.shape[0]), x])

  # 计算数据矩阵x的经济型SVD
  U,S,Vt = linalg.svd(x, full_matrices=False)

  # 求解Ax=b的最小二乘近似解
  x_hat = Vt.T @ linalg.inv(np.diag(S)) @ U.T @ y
  #print(x_hat)

  # 执行训练与测试推理
  #y_pred = x @ x_hat
    
  return y-x @ x_hat     #x_hat

x= direct_ls_svd(A, b)
l2_svd= linalg.norm(A.dot(x) - b)
print("svd: ", l2_svd)

# LU分解求解
x= linalg.solve(A.T@A, A.T@b)
l2_solve= linalg.norm(A.dot(x) - b)
print("scipy.linalg.solve: ", l2_solve)

输出结果:

manually:  2.9751344995811313
scipy.linalg.lstsq:  2.9286130558050654
True
svd:  6.830550019041984
scipy.linalg.solve:  2.928613055805065

疑问解答

1. 差异源于SVD实现错误还是Numpy与Scipy的精度/舍入差异?如何修正SVD最小二乘算法以匹配Scipy结果?

是实现错误,不是精度问题。你的direct_ls_svd函数存在两个关键错误:

  • 错误地给输入矩阵A额外添加了全1偏置列,完全改变了原问题的求解目标(原问题是求Ax=b的最小二乘解,你改成了求[1 A]x=b的解)
  • 函数返回的是残差y-x@x_hat,而非参数向量x_hat,后续用残差当作参数向量计算A.dot(x)-b,逻辑完全错误

修正后的函数如下:

def corrected_ls_svd(A, b):
    # 直接对原矩阵A做经济型SVD,无需额外加偏置列(除非原问题明确需要)
    U, S, Vt = linalg.svd(A, full_matrices=False)
    # 用伪逆替代直接求逆,避免小奇异值导致的数值不稳定
    x_hat = Vt.T @ (linalg.pinv(np.diag(S)) @ (U.T @ b))
    return x_hat

调用修正后的函数:

x_svd = corrected_ls_svd(A, b)
l2_svd_corrected = linalg.norm(A.dot(x_svd) - b)
print("corrected svd: ", l2_svd_corrected)  # 输出会与scipy.linalg.lstsq结果完全一致

2. 该SVD算法是否比迭代最小二乘法更快、更省内存?

分场景判断:

  • 速度:小规模矩阵(如你的4x4示例)下,SVD和迭代法(如梯度下降)速度差异可忽略。但对于大规模、低秩或病态矩阵,SVD(尤其是经济型SVD)通常更快——迭代法需多次迭代收敛,而SVD是底层优化过的BLAS/LAPACK矩阵分解操作,效率更高。
  • 内存:经济型SVD仅存储必要的分解矩阵,比满秩SVD更省内存。但迭代法(如随机梯度下降)支持流式数据处理,内存占用极低,适合无法一次性加载到内存的超大规模数据集。

总结:中小规模矩阵选SVD更高效;超大规模流式数据选迭代法更省内存。

3. 我的最终目标是将SVD应用于PCA、PLS-SVD,其算法是否与最小二乘近似一致?

核心逻辑相通,但应用场景不同:

  • PCA:本质是对数据协方差矩阵做SVD,保留大奇异值对应的特征向量实现降维。其目标是最大化投影后数据的方差,等价于最小化重构误差,和最小二乘的误差最小化思想一致。
  • PLS-SVD:是偏最小二乘的SVD实现,同时对自变量和因变量的协方差结构做分解,寻找既能解释自变量方差又能关联因变量的成分,本质也是通过SVD求解一系列最小二乘问题,只是目标换成了最大化自变量与因变量的协方差。

4. 奇异谱分解中的SVD与用于降维的SVD有何关联?

  • 关联:两者都基于SVD的核心分解逻辑,通过提取奇异值对应的成分来捕捉数据的主要结构。
  • 差异:
    • 用于降维的SVD(如PCA中的SVD):直接对原始数据或协方差矩阵做分解,保留大奇异值对应的成分实现维度压缩。
    • 奇异谱分解(SSA):先将时间序列转化为轨迹矩阵(延迟嵌入),再对轨迹矩阵做SVD,随后根据奇异值分组重构,主要用于时间序列的降噪、分解与预测。

简单来说,SSA是SVD在时间序列数据上的特定应用,通过构造轨迹矩阵将一维序列转化为高维矩阵,再用SVD提取信号成分。

5. PCA用于预检测多重共线性的原理是什么?多重共线性对OLS估计的影响如何?

  • PCA检测多重共线性的原理:多重共线性意味着自变量间存在线性相关,导致协方差矩阵接近奇异(行列式趋近于0)。对协方差矩阵做SVD后,会出现极小的奇异值——因为奇异值的平方对应主成分的方差,小奇异值说明存在可被其他变量线性表示的成分,即存在多重共线性。
  • 多重共线性对OLS的影响:
    • OLS估计的方差显著增大,结果不稳定,微小的数据波动会引发参数大幅变化。
    • 参数的置信区间变宽,显著性检验结果不可靠。
    • 虽OLS估计仍保持无偏性,但不再是有效估计(方差不再最小)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 19:29:56