scipy.optimize.fmin_slsqp的用法

8
我将使用scipy.optimize包来寻找成本函数的最大值。
在这个特定的例子中: 我有一个价格列表,这些价格在一天内变化。为了简单起见,假设一天有8小时,并且每小时的价格如下:
price_list = np.array([1,2,6,8,8,5,2,1])

在这个简化的案例中,我想从价格列表中选择前四个最高的价格。由于各种原因,我不想简单地对价格进行排序并选择最好的四个价格,而是使用一些优化算法。我有几个约束条件,因此我决定使用scipy中的最小二乘算法,即scipy.optimize.fmin_slsqp。
首先,我为我选择的小时创建一个时间表:
schedule_list = np.zeros( len(price_list), dtype=float)

接下来,我需要定义我的倒数利润函数。对于所有选择的时间,我想要将我的利润加总起来。虽然我想要优化我的日程安排,但价格列表是固定的,因此我需要将其放在*args中:

def price_func( schedule_list, *price_list ):
    return -1.*np.sum( np.dot( schedule_list, price_list ) )

一旦我理解了原理,我会移动一些东西。目前为止,我避免使用更多的*args,并通过硬编码运行小时数来定义我的约束条件。我想要选择的小时数恰好为4,因此我使用等式约束:

def eqcon(x, *price_list):
    return sum( schedule_list ) - 4

此外,我希望将我的时间表值限制为0或1。目前我不确定如何实现,因此我只是使用了边界关键字。

有界优化很好用,我只需将我的时间表列表作为第一个猜测即可。

scipy.optimize.fmin_slsqp( price_func, schedule_list, args=price_list, bounds=[[0,1]]*len(schedule_list) )

输出结果是最好的:

Optimization terminated successfully.    (Exit mode 0)
        Current function value: -33.0
        Iterations: 2
        Function evaluations: 20
        Gradient evaluations: 2
Out[8]: array([ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.])

不加任何限制,这是最优解决方案!

使用以下命令的约束优化:

scipy.optimize.fmin_slsqp( price_func, schedule_list, args=price_list, bounds=[[0,1]]*len(schedule_list), eqcons=[eqcon, ] )

出现错误:

Singular matrix C in LSQ subproblem    (Exit mode 6)
        Current function value: -0.0
        Iterations: 1
        Function evaluations: 10
        Gradient evaluations: 1
Out[9]: array([ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.])

我知道从gnuplot得出这通常与无意义的问题或不良初始值有关。我尝试了几乎最优的初始值,但没有帮助。有人有任何想法或者甚至是解决方案吗?

接下来,我已经制定了不等式约束条件。我是否正确地理解,在scipy minimize包装器中,不等式被认为大于0,而在fmin_slsqp中则相反。解决方案受到负约束函数的限制?


1
好的,首要问题是:约束条件在定义中应该与函数中使用的参数相同。不要混淆x和schedule_list。 - Jochen
3个回答

7
您有一个普通的线性程序,是吗?
min: - prices . x
constrain: x >= 0, sum x = 4

因此,二阶导数矩阵(Hessian)恰好为0。
slsqp试图反转这一点,但这是不可能的。同意,错误消息可能会更好些。
(任何包中的其他二次方法都会发生相同的情况:它们在平滑函数上收敛得非常快,但在崎岖悬崖上崩溃。)

另请参见为什么我无法调整scipy有约束优化用于整数规划--但LP应该能胜任(最多4个),整数编程更难。


你确定线性约束引起了这个问题吗?在官方的SciPy SLSQP算法教程中有一个线性约束(y - 1 <= 0)。参考链接:https://docs.scipy.org/doc/scipy/reference/tutorial/optimize.html#tutorial-sqlsp - Marek
@Marek。问题是我认为只有线性约束,二次项为0。 - denis

3

SLSQP算法是一种基于梯度的优化器,这意味着它期望目标函数和约束条件的导数是连续的。从我的理解来看,似乎你正在尝试解决一个整数规划问题(在日程列表中连续值是不可接受的)。你需要一种算法来选择适当的值(0或1)作为独立变量,而不是尝试找到连续值空间的最小值。不幸的是,我不确定scipy中是否有这样的算法。


我应该考虑连续性。但在当前形式下,没有二进制限制的设置是一个连续函数,其导数应该存在。基本上,它是一个简单的多维斜率价格线...好的,后面的限制不是连续的。但这是必要的吗? - Jochen

0

你的代码中有一些错误。正确的代码如下:

1. def price_func( schedule_list, price_list )
2. def eqcon(schedule_list , price_list):
       return sum( schedule_list ) - 4
3. scipy.optimize.fmin_slsqp( price_func, schedule_list, args=(price_list,), bounds=[[0,1]]*len(schedule_list), eqcons=[eqcon, ] )

然后它就可以工作了。


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