Scipy.optimize:如何限制参数值

44

我正在尝试使用scipy.optimize函数来找到一个具有多个参数的复杂函数的全局最小值。其中scipy.optimize.minimize方法似乎是最好的选择,特别是使用'Nelder-Mead'方法。然而,它往往会超出参数域(给只能为正数的参数分配负值),从而在这些情况下返回错误。是否有一种方法可以在scipy.optimize.minimize函数本身中限制参数的边界?或者在其他scipy.optimize函数中?

我发现了以下建议:

当参数超出可接受范围时,请返回一个极大的数字(远离要拟合的数据)。这将(希望)惩罚该参数选择,以至于curve_fit将选择其他可接受的参数集作为最佳参数。

在先前的答案中提供, 但这个过程在我的情况下需要很长的计算时间。


1
当输入超出允许范围时,使代价函数返回一个大的代价是一个非常糟糕的想法,因为搜索函数将会花费大部分精力在不合格答案的无限空间中进行搜索。使用scipy.minimize中的constraint参数来指定一种方法,告诉算法在哪里限制其搜索。在此处搜索“constraints”:http://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html#scipy.optimize.minimize - Eric Leschinski
4个回答

49
minimize函数有一个bounds参数,其中可以在使用L-BFGS-B、TNC、COBYLA或SLSQP方法时限制每个变量的边界。

例如,

import scipy.optimize as optimize

fun = lambda x: (x[0] - 1)**2 + (x[1] - 2.5)**2
res = optimize.minimize(fun, (2, 0), method='TNC', tol=1e-10)
print(res.x)
# [ 1.          2.49999999]

bnds = ((0.25, 0.75), (0, 2.0))
res = optimize.minimize(fun, (2, 0), method='TNC', bounds=bnds, tol=1e-10)
print(res.x)
# [ 0.75  2.  ]

我正在尝试使用优化算法来实现这个,而且我认为限制范围是限制它的地方,但不幸的是,即使我强制设定 (.1,1) 或 (.1,.5) 的限制,我的结果仍然显示为 0。有什么解决方法吗?我是用列表推导式来实现的,所以我的 bnd 是 [(.1,.9) for I in range(15)],在某些情况下,其中一个是 1.0,其他 14 个是 0。 - Zach Oakes
DUH -- .1 不能整除 1.0 15x -- 哎呀!抱歉,我正在使用一个5个证券组合的for循环,并对其进行了缩放,但没有考虑更改最小值。问题已解决。 - Zach Oakes

34

Nelder-Mead求解器不支持约束优化,但有几种其他求解器支持。

TNC和L-BFGS-B仅支持边界约束(例如x [0] > = 0),这对您的情况应该是可以接受的。COBYLA和SLSQP更加灵活,支持任何边界、等式和不等式约束的组合。

您可以通过查看独立函数的文档来获取有关求解器的更详细信息,例如scipy.optimize.fmin_slsqp用于method ='SLSQP'的文档。

您可以在此处查看我的先前答案,了解使用SLSQP进行约束优化的示例。


我刚刚检查了SciPy 1.7.1,他们允许通过根据边界剪裁simplex来为Nelder-Mead算法设置边界。 - Daniel Casas-Orozco

13

你要查找的参数是:constraints,它是传递给scipy.minimize的参数之一。编写自己的lambda函数来约束参数,如下:

The argument you are looking for is: constraints which is one of the arguments passed to scipy.minimize. Roll your own lambda function that receives the parameters to constrain like this:

#A function to define the space where scipy.minimize should 
#confine its search:
def apply_sum_constraint(inputs):
    #return value must come back as 0 to be accepted
    #if return value is anything other than 0 it's rejected
    #as not a valid answer.
    total = 50.0 - np.sum(inputs)
    return total

my_constraints = ({'type': 'eq', "fun": apply_sum_constraint })
result = spo.minimize(f, 
                      guess, 
                      method='SLSQP', 
                      args=(a, b, c),
                      bounds=((-1.0, 1.0), (-1.0, 1.0)),
                      options={'disp': True},
                      constraints=my_constraints)

上面的例子断言,最后搜索项附近的所有新候选项加起来应该等于50。将该方法更改为定义可允许的搜索空间,scipy.minimize函数将不会浪费精力考虑这些答案。


3
我知道这已经晚了,但也许可以看看 mystic。你可以在任何优化器(包括来自scipy.optimize.fmin的算法)上应用任意Python函数作为惩罚函数,或应用边界约束等等...。 https://github.com/uqfoundation/mystic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接