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

如何用Scipy在截距b≤0约束下最小化线性回归残差平方和

基础定义校验
  • 你定义的模型函数f是完全正确的,和常规线性回归形式y = a*x + b完全匹配。
  • 你定义的目标函数obj计算结果是正确的:对残差取绝对值后再平方,和直接对残差取平方的计算结果完全等价(平方操作本身会消除正负差异),只是写法存在冗余,可以简化为np.sum((y - f(x, a, b))**2),计算效率更高。
满足b ≤ 0约束的残差平方和最小化实现

带截距非正约束的最小二乘属于凸优化问题,有两种非常高效的实现方式,不需要你自己手写复杂的约束判断逻辑:

方法一:解析法直接计算结果

这个方法不需要调用优化库,逻辑完全基于凸优化的KKT条件,计算速度最快:

  1. 先计算无约束OLS的常规最优解,得到无约束下的截距值b_unc
  2. 如果b_unc ≤ 0,说明无约束解本身就满足约束要求,直接使用无约束的拟合结果即可
  3. 如果b_unc > 0,那么带约束的最优解一定在约束边界b = 0的位置,此时模型退化为强制过原点的线性回归,直接拟合y = a*x即可得到约束下的最小残差平方和

对应实现代码:

import numpy as np

# 转换输入为numpy数组
x_arr = np.array(x)
y_arr = np.array(y)

# 计算无约束OLS的最优参数
x_mean = np.mean(x_arr)
y_mean = np.mean(y_arr)
a_unc = np.sum((x_arr - x_mean) * (y_arr - y_mean)) / np.sum((x_arr - x_mean) ** 2)
b_unc = y_mean - a_unc * x_mean

# 按约束规则选择最终参数
if b_unc <= 0:
    final_a, final_b = a_unc, b_unc
else:
    # 强制b=0,拟合过原点的回归
    final_a = np.sum(x_arr * y_arr) / np.sum(x_arr ** 2)
    final_b = 0

# 计算最终残差平方和
sse = np.sum((y_arr - (final_a * x_arr + final_b)) ** 2)

方法二:带边界约束的通用优化器求解

如果你需要更通用的框架适配后续其他约束,可以直接给优化器添加参数边界约束,直接把截距b的上限设为0即可,不需要额外写约束判断逻辑:

from scipy.optimize import minimize

def objective(params):
    a, b = params
    return np.sum((y_arr - (a * x_arr + b)) ** 2)

# 参数边界定义:
# 第一个参数a不做上下限约束(用None表示)
# 第二个参数b上限为0,自动满足b ≤ 0的要求
bounds = [(None, None), (None, 0)]

# 从初始值开始优化
opt_result = minimize(objective, x0=[1, 0], bounds=bounds)
final_a, final_b = opt_result.x
sse = opt_result.fun

两种方法得到的最优参数结果完全一致,因为带不等式约束的二次凸优化不存在局部最优解,解析法可以直接得到全局最优值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.28 11:36:03