为何numpy最小二乘求解结果正确,scipy却得出异常结果?
为啥numpy和scipy最小二乘结果差这么大?
嘿,这个问题我太熟了!我来帮你拆解一下为啥会出现这种离谱的差异~
核心原因:两者的求解逻辑根本不一样
这两个函数看起来都是“最小二乘”,但本质完全不同:
numpy.linalg.lstsq:是专门为线性最小二乘设计的工具,它直接通过矩阵分解(比如QR分解)来求解,属于解析解法,结果稳定、唯一,完全适合你这种线性回归场景(y = X @ p)。scipy.optimize.leastsq:是一个通用的非线性最小二乘优化器,它靠迭代搜索来找到残差平方和最小的参数。它不仅能处理线性问题,更擅长非线性,但代价是需要你提供初始参数猜测,而且对初始值非常敏感——如果初始值给得太离谱,很容易发散到奇怪的结果,甚至每次迭代的数值误差都会导致结果不一样。
你大概率踩了这几个坑
结合你的描述,问题几乎肯定出在scipy的使用方式上:
- 初始参数
x0给得太离谱
如果你没指定初始值,或者给了比如[0,0]、随机值,甚至极端大的数,对于线性问题来说,迭代过程可能直接发散,得到你看到的那种超大数值结果。 - 残差函数构造错误
比如你把残差写成了X @ p - y(虽然平方和一样,但优化方向可能有影响),或者函数逻辑写错了,导致优化器找错方向。 - 没调整优化参数
比如迭代次数不够(maxfev参数),或者公差设置太松,导致优化器还没收敛就停止了。
正确使用scipy leastsq的示例
给你写个对比代码,照着改就能得到和numpy一致的结果:
import numpy as np from scipy.optimize import leastsq # 先构造模拟数据(和你的场景一致) X = np.random.rand(100, 2) * 10 true_params = np.array([9.94, 5.06]) y = X @ true_params + np.random.randn(100) * 0.5 # numpy的解法(稳定可靠) p_np, _, _, _ = np.linalg.lstsq(X, y, rcond=None) print("numpy求解结果:", p_np) # scipy的正确解法 def residual(params, X, y): # 残差必须是 y - 预测值,也就是真实值减模型输出 return y - X @ params # 给一个合理的初始猜测!比如接近真实值的数,或者全1都可以 initial_guess = np.array([1, 1]) p_scipy, _ = leastsq(residual, initial_guess, args=(X, y)) print("scipy正确求解结果:", p_scipy)
总结建议
- 如果是线性回归问题,优先用numpy的lstsq或者sklearn的LinearRegression,它们是专门为这类问题设计的,速度快、结果稳定,sklearn的LinearRegression底层其实也是用类似的线性代数方法,所以和numpy结果一致是正常的。
- 非要用scipy leastsq的话,一定要给合理的初始参数,并且确保残差函数正确。
内容的提问来源于stack exchange,提问作者deepak
相关产品推荐
相关产品推荐

