【问题标题】:Minimize a function with SciPy with constraints and bounds使用具有约束和边界的 SciPy 最小化函数
【发布时间】:2020-03-22 07:20:00
【问题描述】:

我有一系列收取利率的账户,我每天都必须决定从哪个账户借钱。我对每个帐户都有借款限额。 显然,最简单的答案是先用尽最便宜的价格,依此类推。

由于我们必须每天计算几次,账户的数量会有所不同,我们计划了一个前滚现金流,我正在尝试编写一些 Python 代码以使其自动化。

最小化的目标函数是加权平均利率,确定从每个账户 (x) 借的钱,范围从 0 到整数(取决于每个协议),以支付未偿还的款项。

下面的代码似乎运行良好,但我在一张纸上进行了数学计算,但没有达到全局最小值。我有什么遗漏吗?

import numpy as np
from scipy.optimize import minimize

outstanding = -106332403


limit = [15000000, 29250000, 15000000, 22000000, 52567324, 5000000, 5000000, 40000000, 7398262]
interest = [0.73, 0.63, 0.78, 0.75, 0.6084, 0.97, 0.84, 0.625, 0.40]

limit = np.asarray(limit)
interest = np.asarray(interest)

def objective(x):
    product = x * interest
    sumproduct = sum(product)
    return sumproduct / -outstanding

def constraint1(x):
    return sum(x) + outstanding

# initial guesses
n = len(interest)
x0 = [1,1,1,1,1,1,1,1,1]

bnds = []

for value in limit:
    b= (0,value)
    bnds.append(b)


con1 = {'type': 'eq', 'fun': constraint1}
cons = (con1)

solution = minimize(objective,x0,method='SLSQP',bounds=bnds,constraints=cons)

x = solution.x

【问题讨论】:

  • 您的预期结果是什么(这样其他人就不必费心区分您的功能了)?你的问题似乎是线性的。你真的需要 SLSQP 来解决它吗?对于线性问题可能不是最好的算法。
  • 谢谢@onodip。不,我真的不需要 SLSQP。我刚刚尝试过,因为它接受界限和约束。你不需要区分。预期结果建议首先使用较低利率的协议:730 万在 40%/5200 万在 60.84%/4000 万在 62.5%,其余约 700 万在 63%。其余的不应使用,因此它们将为 0。
  • 所以数组结果(以百万计)应该是:(0, 7, 0, 0, 52.6, 0, 0, 40, 7.3)
  • 使用此解决方案,您的等式约束不满足。我得到它的值 567597.0,它应该是零。在这种简单的情况下,它不会造成麻烦,但是您的目标和约束也是一个非常不同的数量级,将其标准化是一种很好的做法。对于我在X = [14844753.39667935,14844753.39667935,14844753.39667935,14844753.39667935,14844753.39667935,4955206.87349367,4955206.87349367,14844753.39667935,7353468.87293655]和客观= 0.6876659050587411 跨度>优化结果
  • 是的。这就是产生的解决方案。但这是不正确的,我不知道为什么。我告诉的解决方案 (0, 7, 0, 0, 52.6, 0, 0, 40, 7.3) 是近似数字,这就是为什么你没有在约束中达到 0。问题是 scipy 没有达到最小值,我不知道为什么。

标签: python optimization scipy minimize


【解决方案1】:

我对您的脚本进行了一些更改。最重要的是设置更大的最大迭代次数,并在有限差分步长和收敛容差方面发挥作用。我还重写了您的目标,以更改数量级。这样我得到的解决方案接近您在评论中提供的值。

import numpy as np
from scipy.optimize import minimize

outstanding = -106332403


limit = np.array([15000000, 29250000, 15000000, 22000000, 52567324, 5000000, 5000000, 40000000, 7398262])
interest = np.array([0.73, 0.63, 0.78, 0.75, 0.6084, 0.97, 0.84, 0.625, 0.40])

# initial guesses
n = len(interest)
x0 = np.ones(len(interest)) * 1e6 * 1

def objective(x):
    return np.dot(x, interest)

def constraint1(x):
    con = sum(x) + outstanding
    return con

bnds = [(0, value) for value in limit]

con1 = {'type': 'eq', 'fun': constraint1}

solution = minimize(objective,x0,method='SLSQP',bounds=bnds,constraints=con1, 
                    options={"eps": 01e-3, "maxiter": 1000}, tol=1e-8)

print(solution)

结果:

     fun: 63952359.431600004
     jac: array([0.72999299, 0.62999874, 0.77999383, 0.74999779, 0.60839951,
       0.96999854, 0.84000081, 0.6249994 , 0.40000677])
 message: 'Optimization terminated successfully.'
    nfev: 1635
     nit: 147
    njev: 145
  status: 0
 success: True
       x: array([0.00000000e+00, 6.36681700e+06, 0.00000000e+00, 0.00000000e+00,
       5.25673240e+07, 1.77575799e-16, 2.32417370e-17, 4.00000000e+07,
       7.39826200e+06])

【讨论】:

  • 它适用于不同的初始值,包括原始代码中的值。
  • 太棒了!非常感谢。
猜你喜欢
  • 2016-05-27
  • 2019-02-04
  • 1970-01-01
  • 2013-12-03
  • 2013-09-17
  • 2021-07-03
  • 2017-07-07
  • 2020-08-08
  • 2014-11-18
相关资源
最近更新 更多