scipy least_squares如何添加变量间等式约束
实现方案
scipy.optimize.least_squares 原生仅支持变量的上下界约束,不支持变量间的等式/不等式约束,针对你提出的两个线性等式约束场景,有两种可直接落地的实现方式:
方案1:参数消元(最推荐,无精度损失,实现最简单)
你的两个约束是完全线性的,可以直接通过变量替换消去约束,把带约束问题转成无约束最小二乘问题,完全兼容现有least_squares的调用逻辑。
假设你的两个固定约束值为:
x - y = c1(c1为你指定的固定常数)z - y = c2(c2为你指定的固定常数)
那么可以直接把x、z用唯一的自由变量y表示:x = y + c1z = y + c2
原来的3个优化变量直接缩减为1个自由变量y,优化过程中x、z会自动满足约束条件,不需要额外做约束处理。
代码示例:
from scipy.optimize import least_squares # 定义约束的固定值,替换为你实际需要的数值即可 c1 = 2 # 对应约束x-y=2 c2 = 3 # 对应约束z-y=3 def loss_func(free_y, *arguments): # 从自由变量恢复x,y,z,天然满足预设约束 x = free_y + c1 y = free_y z = free_y + c2 # 下方保留你原有的残差计算逻辑即可 loss = [] # 替换为你实际的残差数组计算逻辑 return loss # 初始值只需要传入自由变量y的初始值即可,直接从原初始数组中取y的初始值 y_init = x_arr[1] # x_arr为你原来存储x,y,z初始值的数组 res = least_squares(loss_func, y_init, args=arguments) # 优化完成后恢复x,y,z的最优结果 opt_y = res.x[0] opt_x = opt_y + c1 opt_z = opt_y + c2
方案2:改用支持约束的优化接口(适合约束复杂、不便消元的场景)
如果后续约束变复杂无法直接消元,可以放弃least_squares,改用scipy.optimize.minimize接口,自己构造最小二乘目标函数(即残差平方和),同时传入等式约束即可。
代码示例:
import numpy as np from scipy.optimize import minimize # 定义约束的固定值,替换为你实际需要的数值即可 c1 = 2 c2 = 3 def obj_func(x_arr, *arguments): x, y, z = x_arr # 计算你原来定义的残差数组 resi = [] # 替换为你原来loss_func中的残差计算逻辑,返回数组格式 # 最小二乘的优化目标是残差平方和最小 return np.sum(np.array(resi)**2) # 定义等式约束 constraints = [ {"type": "eq", "fun": lambda x: x[0] - x[1] - c1}, # 对应约束x-y = c1 {"type": "eq", "fun": lambda x: x[2] - x[1] - c2} # 对应约束z-y = c2 ] # 传入初始值、约束、其他参数启动优化 res = minimize(obj_func, x_arr, args=arguments, constraints=constraints) # 最优x,y,z结果直接从res.x中读取即可 opt_x, opt_y, opt_z = res.x
注意:如果你的残差计算逻辑没有特殊的强非线性复杂度,优先选择方案1,消元后用原生
least_squares的求解效率和精度都高于通用带约束优化器。
内容的提问来源于stack exchange,提问作者Hai Le
相关产品推荐
相关产品推荐

