如何用Scipy在截距b≤0约束下最小化线性回归残差平方和
基础定义校验
- 你定义的模型函数
f是完全正确的,和常规线性回归形式y = a*x + b完全匹配。 - 你定义的目标函数
obj计算结果是正确的:对残差取绝对值后再平方,和直接对残差取平方的计算结果完全等价(平方操作本身会消除正负差异),只是写法存在冗余,可以简化为np.sum((y - f(x, a, b))**2),计算效率更高。
满足
b ≤ 0约束的残差平方和最小化实现 带截距非正约束的最小二乘属于凸优化问题,有两种非常高效的实现方式,不需要你自己手写复杂的约束判断逻辑:
方法一:解析法直接计算结果
这个方法不需要调用优化库,逻辑完全基于凸优化的KKT条件,计算速度最快:
- 先计算无约束OLS的常规最优解,得到无约束下的截距值
b_unc - 如果
b_unc ≤ 0,说明无约束解本身就满足约束要求,直接使用无约束的拟合结果即可 - 如果
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
相关产品推荐
相关产品推荐

