使用矩阵约束的scipy.optimize.minimize
我刚接触scipy.optimize模块,正在使用它的minimize函数,想要找到一个x值,使得一个多变量函数的值最小化。这个函数接受一个矩阵作为输入,但返回的是一个标量值。我有一个等式约束和一个不等式约束,它们都接受向量作为输入,并返回向量值。具体来说,这里是约束的列表:
sum(x) = 1 ;
AST + np.log2(x) >= 0
其中AST
只是一个参数。我定义了我的约束函数,如下所示:
对于等式约束:lambda x: sum(x) - 1
对于不等式约束:
def asset_cons(x):
#global AST
if np.logical_and.reduce( (AST + np.log2(x)) >= 0):
return 0.01
else:
return -1
然后我调用了
cons = ({'type':'eq', 'fun': lambda x: sum(x) - 1},
{'type':'ineq', 'fun': asset_cons})
res = optimize.minize(test_obj, [0.2, 0.8], constraints = cons)
但是我还是遇到了错误,提示我的约束函数有问题。约束函数可以返回向量值吗,还是说我必须返回一个标量值才能使用这个minimize函数?
有没有人能帮我看看我指定约束的方式有没有问题?
1 个回答
从原则上讲,这看起来并没有太大问题。不过,如果不看到关于 test_obj
的一些信息和实际的错误,很难判断。是抛出了异常(这可能是编程上的错误),还是对收敛性有抱怨(这可能是数学上的挑战)?
你的基本思路是对的;你需要一个函数,它能接受一个包含 N 个元素的输入向量,并返回一个需要最小化的值。你的边界条件也应该接受同样的输入向量,并返回一个单一的标量作为输出。
在我看来,你的边界条件有点问题。第一个条件(sum(x) - 1
)是没问题的,但第二个条件在数学上有点挑战,因为你把它定义成了一个分段函数。很多优化算法希望使用连续的函数,最好是比较平滑的那种。(我不知道这个函数使用的算法是否能很好地处理分段函数,所以这只是我的猜测。)
如果以上说的都成立,你可以通过以下方式简化问题:
np.amin(AST + np.log2(x))
如果所有的 AST + log2(x[n]) >= 0
,那么这个函数将是非负的。(虽然它仍然不是特别平滑,但如果这是个问题,改进起来也不难。)现在它也可以放进一个 lambda
函数里。
如果你在收敛性上遇到困难,可能应该尝试 COBYLA 和 SLSQP 两种方法,除非你已经知道其中一种对你的问题更好。