【问题标题】:scipy.optimize.minimize constraints problemscipy.optimize.minimize 约束问题
【发布时间】:2021-11-13 23:55:36
【问题描述】:

我有一个最小化任务: 该功能工作正常:

def list_year_payments(clear_payments, number_periods):
    payments = clear_payments[:number_periods+1]
    eq_const = {'type':'eq', 'fun': lambda x:   np.sum(x*discoun_coeff(number_periods,d_r))-future_value_of_aim}
    eq_const_1 = {'type':'eq', 'fun': lambda x: (payments[0]/x[0] - payments[1]/x[1])}
    eq_const_2 = {'type':'eq', 'fun': lambda x: (payments[1]/x[1] - payments[2]/x[2])}
    eq_const_3 = {'type':'eq', 'fun': lambda x: (payments[2]/x[2] - payments[3]/x[3])}
    eq_const_4 = {'type':'eq', 'fun': lambda x: (payments[3]/x[3] - payments[4]/x[4])}
    eq_const_5 = {'type':'eq', 'fun': lambda x: (payments[4]/x[4] - payments[5]/x[5])}
    eq_const_6 = {'type':'eq', 'fun': lambda x: (payments[5]/x[5] - payments[6]/x[6])}
    bounds = ((0,70),)*(number_periods+1)
    res = minimize(aim, X, method='SLSQP', constraints=[eq_const,eq_const_1, eq_const_2,eq_const_3,eq_const_4,eq_const_5, eq_const_6] , bounds=bounds)
    return res.x

但实际上所有的约束都依赖于 '''number_periods''':所以我需要一条指令来处理 6 到 6 的所有约束。

def minimizze(clear_payments, number_periods):
    payments = clear_payments[:number_periods+1]
    eq_const = {'type':'eq', 'fun': lambda x: np.sum(x*discoun_coeff(number_periods,d_r))-future_value_of_aim}
    eq_const_1 = {'type':'eq', 'fun': lambda x : np.sum([payments[i]/x[i] ==    payments[i+1]/x[i+1] for i in range(number_periods)])-number_periods}

    bounds = ((1,70),)*(number_periods+1)
    res = minimize(aim, X, method='SLSQP', constraints=[eq_const,eq_const_1] , bounds=bounds)
    return res.x

但这不起作用返回开始 x 迭代的数组(如 [1,1,1,1,1,1,1]),看起来应该是 470 的总和的 eq_const 不起作用。

所有代码:

import numpy as np
from scipy.optimize import minimize

clear_payments = np.array([90,100,110,120,130,120,110,100,90])
future_value_of_aim = 470
number_periods = 6
d_r = 0.12


def discoun_coeff(per,d_r):
    x = np.ones(per+1)
    k = np.empty(per+1)
    for i in range(per+1):
        k[i]=x[i]*(1+d_r)**i

    return k[::-1]


def aim(X):
    return np.sum(X)

X = np.ones(number_periods+1)
x = np.linspace(0,70,7000)
def paymets_year(clear_payments, number_periods):
    payments = clear_payments[:number_periods+1]

    eq_const = {'type':'eq', 'fun': lambda x: np.sum(x*discoun_coeff(number_periods,d_r))-future_value_of_aim}

    eq_const_1 = {'type':'eq', 'fun': lambda x: (payments[0]/x[0] - payments[1]/x[1])}
    eq_const_2 = {'type':'eq', 'fun': lambda x: (payments[1]/x[1] - payments[2]/x[2])}
    eq_const_3 = {'type':'eq', 'fun': lambda x: (payments[2]/x[2] - payments[3]/x[3])}
    eq_const_4 = {'type':'eq', 'fun': lambda x: (payments[3]/x[3] - payments[4]/x[4])}
    eq_const_5 = {'type':'eq', 'fun': lambda x: (payments[4]/x[4] - payments[5]/x[5])}
    eq_const_6 = {'type':'eq', 'fun': lambda x: (payments[5]/x[5] - payments[6]/x[6])}
    bounds = ((0,70),)*(number_periods+1)
    res = minimize(aim, X, method='SLSQP', constraints=[eq_const,eq_const_1,       eq_const_2,eq_const_3,eq_const_4,eq_const_5, eq_const_6] , bounds=bounds)
    return res.x

p=paymets_year(clear_payments, number_periods)
p
array([38.34895684, 42.60995205, 46.87094726, 51.13194246, 55.39293767,
   51.13194246, 46.87094726])

【问题讨论】:

  • 你能把 res.message 和 res.success 贴出来吗?

标签: python optimization scipy constraints minimize


【解决方案1】:

如果我理解正确,你想概括一下

 {'type':'eq', 'fun': lambda x: (payments[0]/x[0] - payments[1]/x[1])}
 {'type':'eq', 'fun': lambda x: (payments[1]/x[1] - payments[2]/x[2])}
 {'type':'eq', 'fun': lambda x: (payments[2]/x[2] - payments[3]/x[3])}
 {'type':'eq', 'fun': lambda x: (payments[3]/x[3] - payments[4]/x[4])}
 {'type':'eq', 'fun': lambda x: (payments[4]/x[4] - payments[5]/x[5])}
 {'type':'eq', 'fun': lambda x: (payments[5]/x[5] - payments[6]/x[6])}

对于number_periods = 6 以外的其他值,您尝试使用

 {'type':'eq', 'fun': lambda x : np.sum([payments[i]/x[i] ==    payments[i+1]/x[i+1] for i in range(number_periods)])-number_periods}

但失败了,尽管理论上计算是等效的。但实际上,由于== 关系的不连续性以及浮点运算的不精确性,优化可能会失败。
更好的方法会与原始方法更相似:

 {'type': 'eq',
  'fun': lambda x: np.sum([(payments[i]/x[i]-payments[i+1]/x[i+1])**2 for i in range(number_periods)])
 }

这里像以前一样使用减法,为了让等商的总和接近零,个体差异被平方。
但请注意:使用这个单一约束总结了原始约束,优化的收敛性相当差。更好地继续使用单个约束;您可以为任何number_periods 生成它们:

    constr = [eq_const]
    for i in range(number_periods):
        constr.append({'type': 'eq', 'fun': lambda x, i=i: payments[i]/x[i]-payments[i+1]/x[i+1]})
    res = minimize(aim, X, method='SLSQP', constraints=constr, bounds=bounds)

【讨论】:

  • 非常感谢。还有一个问题,为什么要在 lambda 函数中初始化 $i=i$?
  • 如果我不使用i=i,则 lambda 函数在循环中定义时不会“记住”i 的值,而是使用任何值 @987654330 @ 在他们调用的时候有,所以不能正常工作。
猜你喜欢
  • 1970-01-01
  • 2015-01-02
  • 2014-08-15
  • 2019-04-10
  • 2015-03-07
  • 2016-02-04
  • 2016-06-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多