如何用scipy minimize最小化两向量差并正确配置约束
正确实现方法
你的原有代码存在3个核心错误,也是导致运行挂起的直接原因,对应修正逻辑如下:
- Bounds长度必须和优化变量总长度(200)匹配,不能只传入100个值。要固定w1,只需将Bounds中前100位的上下界都设为初始w1的取值,优化器就无法修改这部分参数;仅给后100位(对应w2)设置
|w2_i|<0.01的取值范围即可,注意严格小于的开区间约束需要留极小的数值余量适配数值优化逻辑。 sum(abs(w2))包含绝对值运算,不属于线性变换,无法用LinearConstraint实现;且你原有线性约束的权重矩阵把w1部分也纳入了求和范围,逻辑完全错误。这个L1范数约束需要用NonlinearConstraint定义。- 原有Bounds错误给固定w1也加上了[-0.01, 0.01]的限制,既没实现锁死w1的要求,还会和固定w1的需求产生逻辑冲突,导致可行域异常。
可直接运行的修正代码
import numpy as np from scipy.optimize import minimize, Bounds, NonlinearConstraint def diff(w: np.ndarray) -> float: """Get the sum of absolute differences in the vector w. Args: w: A flattened vector of length 200, with the first 100 elements pertaining to w1, and the last 100 elements pertaining to w2. Returns: sum of absolute differences. """ return np.sum(np.absolute(w[:100] - w[-100:])) # ------------ 约束定义 ------------ eps = np.finfo(np.float64).eps # 构造长度为200的上下界数组 lb = np.empty(200) ub = np.empty(200) # 前100位w1锁死:上下界与初始值完全一致,禁止修改 lb[:100] = w_init[:100] # w_init是你传入x0的初始展平向量,前100位为固定w1 ub[:100] = w_init[:100] # 后100位w2满足|w2_i| < 0.01,留极小数值余量适配严格不等要求 lb[-100:] = -0.01 + eps ub[-100:] = 0.01 - eps bounds = Bounds(lb=lb, ub=ub) # 定义w2绝对值和的非线性约束:0.1 <= sum(abs(w2)) <=1.1 def w2_l1_norm(w): return np.sum(np.abs(w[-100:])) l1_constraint = NonlinearConstraint(fun=w2_l1_norm, lb=0.1, ub=1.1) # ------------ 优化调用 ------------ res = minimize( fun=diff, method='trust-constr', x0=w_init, bounds=bounds, constraints=[l1_constraint] )
可选优化(加速收敛)
如果运行速度慢,可以手动传入目标函数和约束的雅可比(梯度),避免优化器用有限差分计算梯度拖慢速度:
- 目标函数
diff的梯度:前100位(w1位置)梯度为np.sign(w[:100] - w[-100:]),后100位(w2位置)梯度为-np.sign(w[:100] - w[-100:]) - L1约束的梯度:后100位为
np.sign(w[-100:]),前100位为0
注意:如果固定的w1本身存在绝对值大于等于0.01的元素完全不会影响运行,因为w1部分已经被Bounds锁死,[-0.01, 0.01]的取值限制仅作用于w2部分。
内容的提问来源于stack exchange,提问作者PyRsquared
相关产品推荐
相关产品推荐

