为何更大的边界范围会导致函数最小化结果变差?
目标函数定义
betas = [0.1, 0.2, 0.3] weights = [0.2, 0.2, 0.6] def get_beta_p(betas, weights): return sum([x * y for x, y in zip(betas, weights)])
初始化参数、约束与边界设置
initializer = weights constraints = ({'type' : 'eq', 'fun': lambda x: np.sum(x) -1}, {"type" : "ineq", "fun" : lambda betas: minimize_beta(initializer, betas)}) # sum = 1, fun = 0 bounds = tuple((0, 0.4) for x in range(len(weights))) # x from 0 to 0.4
最小化执行代码
def minimize_beta(weights, args): betas = args return get_beta_p(betas, weights) zero_beta=optimize.minimize(minimize_beta, initializer, method = 'SLSQP', args = betas, bounds = bounds, constraints = constraints)
原本认为优化精度不应受边界范围影响,但实际结果却与预期相悖,不同边界下优化结果差异显著:
- 边界设为
(-0.1, 0.5)时输出:
[array([1.]), array([0.23947614]), array([0.15513421]), array([0.30120484]), array([0.36498963]), array([0.6351255]), array([0.06166346]), array([0.12740605]), array([0.55059138]), array([0.46437143]), array([0.42777512])]
message: Optimization terminated successfully
success: True
status: 0
fun: -0.15440870412170832 #look here
x: [-1.000e-01 2.000e-01 5.000e-01 -1.000e-01 -1.000e-01
-1.000e-01 5.000e-01 5.000e-01 -1.000e-01 -1.000e-01
-1.000e-01]
nit: 5
jac: [ 1.000e+00 2.395e-01 1.551e-01 3.012e-01 3.650e-01
6.351e-01 6.166e-02 1.274e-01 5.506e-01 4.644e-01
4.278e-01]
nfev: 60
njev: 5
- 边界设为
(0, 0.2)时输出:
fun: 0.17697693990449903 x: [ 2.224e-17 2.000e-01 2.000e-01 2.000e-01 0.000e+00 2.898e-16 2.000e-01 2.000e-01 4.457e-16 0.000e+00 0.000e+00]
- 边界设为
(0, 0.4)时输出:
fun: 0.106654645436427
x: [ 2.361e-16 1.700e-16 2.000e-01 8.746e-16 2.980e-16 0.000e+00 4.000e-01 4.000e-01 3.434e-16 6.155e-17 0.000e+00]
- 边界设为
(0.0, 0.5)时输出:
fun: 0.09453475545362894 x: [ 4.951e-16 0.000e+00 0.000e+00 2.505e-16 5.714e-16 0.000e+00 5.000e-01 5.000e-01 6.418e-16 4.344e-16 5.516e-17]
- 边界设为
(0.0, 0.9)时输出:
fun: 0.06823772147966463 x: [ 8.633e-16 0.000e+00 0.000e+00 5.373e-16 1.113e-15 4.327e-17 9.000e-01 1.000e-01 5.260e-16 1.818e-17 0.000e+00]for (-0.2, 0.2)
疑问:这种情况是否正常?为何优化结果会如此不稳定?
这种情况是正常的,核心原因在于优化问题本身及代码逻辑的问题:
目标函数的线性特性
目标函数get_beta_p是线性函数(权重与beta的加权和),线性优化问题的最优解必然出现在可行域的顶点或边界上。调整边界范围会直接改变可行域的形状和顶点位置,最优解自然会随之变化——这不是精度问题,是线性优化的固有特性。约束设置存在逻辑错误
不等式约束{"type" : "ineq", "fun" : lambda betas: minimize_beta(initializer, betas)}等价于要求目标函数值≥0,这给目标函数加了下界约束。调整边界时,可行域满足该约束的情况会变化,进一步影响最优解的位置。参数传递与维度混乱
从输出的x维度(11个元素)来看,实际的weights或betas维度与代码中定义的[0.2,0.2,0.6]不符,导致目标函数计算逻辑混乱。另外,optimize.minimize的args参数传递错误:minimize_beta的第一个参数是weights,但调用时把betas传给了args,造成参数错位,计算出的目标值完全不符合预期。SLSQP算法的边界敏感性
SLSQP算法针对带约束优化场景,对于线性目标+边界/约束变化的情况,会直接在可行域的边界上寻找最优解,不同边界范围会锁定不同的最优顶点,因此结果差异显著是必然的。
内容的提问来源于stack exchange,提问作者Blob

