【问题标题】:Optimize a non linear function in python在python中优化非线性函数
【发布时间】:2018-06-26 07:50:01
【问题描述】:

我在 python 中有一个函数,如下所示:

import numpy as np    

def fun(Gp,Ra,Mr,Pot,Sp,Mc,Keep):
   if(Keep==True):
     return(Pot*np.tanh((Gp+Ra+Mr+ Mc)*Sp ))

假设以下数据:

   import pandas as pd
dt_org = pd.DataFrame({"RA": [0.5, 0.8, 0.9],
                   "MR": [0.97, 0.95, 0.99],
                   "POT": [0.25, 0.12, 0.05],
                   "SP": [0.25, 0.12, 0.15],
                   "MC": [50, 75, 100],
                   "COUNTRY": ["GB", "IR", "GR"]
                   })

我总共有 100 GP 我想正确分配所有这些 为了最大化objective_function

all这3个元素都是

的限制下

根据this 发布scipy.optimize 将是要走的路,但我很困惑如何写下问题

更新:我的尝试

from scipy.optimize import minimize

y = {'A': {'RA': 0.5, 'MR': 0.97, 'POT': 0.25, 'SP': 0.25, 'MC': MC_1, 'keep': True},
     'B': {'RA': 0.8, 'MR': 0.95, 'POT': 0.12, 'SP': 0.12, 'MC': MC_2, 'keep': True},
         'C': {'RA': 0.9, 'MR': 0.99, 'POT': 0.05, 'SP': 0.15, 'MC': MC_3, 'keep': True}}

def objective_function(x):
                return(
                     -(fun(x[0], Ra=y['A']['RA'], Mr=y['A']['MR'],
                                             Pot=y['A']['POT'], Sp=y['A']['SP'],
                                             Mc=y['A']['MC'], Keep=y['A']['keep']) +
                       fun(x[1], Ra=y['B']['RA'], Mr=y['B']['MR'],
                                             Pot=y['B']['POT'], Sp=y['B']['SP'],
                                             Mc=y['B']['MC'], Keep=y['B']['keep']) +
                       fun(x[2], Ra=y['C']['RA'], Mr=y['C']['MR'],
                                             Pot=y['C']['POT'], Sp=y['C']['SP'],
                                             Mc=y['C']['MC'], Keep=y['C']['keep']))
                )

cons = ({'type': 'ineq', 'fun': lambda x:  x[0] + x[1] + x[2] - 100})

bnds = ((0, None), (0, None), (0, None))

minimize(objective_function, x0=[1,1,1],   args=y, method='SLSQP', bounds=bnds,
             constraints=cons)

现在的问题是我得到了错误ValueError: Objective function must return a scalar,而fun 函数的输出是一个标量

更新 2(@Cleb 评论后) 所以现在我改变了函数:

def objective_function(x,y):

                temp =   -(fun(x[0], Ra=y['A']['RA'], Mr=y['A']['MR'],
                                             Pot=y['A']['POT'], Sp=y['A']['SP'],
                                             Mc=y['A']['MC'], Keep=y['A']['keep']) +
                       fun(x[1], Ra=y['B']['RA'], Mr=y['B']['MR'],
                                             Pot=y['B']['POT'], Sp=y['B']['SP'],
                                             Mc=y['B']['MC'], Keep=y['B']['keep']) +
                       fun(x[2], Ra=y['C']['RA'], Mr=y['C']['MR'],
                                             Pot=y['C']['POT'], Sp=y['C']['SP'],
                                             Mc=y['C']['MC'], Keep=y['C']['keep']))


                print("GP for the 1st: " + str(x[0]))
                print("GP for the 2nd: " + str(x[1]))
                print("GP for the 3rd: " + str(x[2]))
        return(temp)

cons = ({'type': 'ineq', 'fun': lambda x:  x[0] + x[1] + x[2] - 100})

bnds = ((0, None), (0, None), (0, None))

现在有两个问题: 1.x[0],x[1],x[2]的值真的很接近

  1. x[0],x[1],x[2]的总和超过100

【问题讨论】:

  • 阅读他们的教程(scipy.optimize; tutorial != API docs; 它非常好)并尝试一下。您可能会感到困惑,但不尝试并显示任何东西总是看起来像:为我编写代码。
  • 请看更新
  • 这是代码,但没有说明它存在的潜在问题。
  • 我可能会错过一些东西,但在您的objective_function 中,您只通过x 而不是y;在fun 你只传递参数但没有x(这个函数似乎独立于x,这看起来很时髦)。我也同意 sascha:一个实际的问题会帮助你:)
  • @Cleb 我在minimize 函数的args 参数中传递了y。现在的问题是我得到了错误ValueError: Objective function must return a scalar,而fun 函数的输出是一个标量

标签: python python-3.x numpy optimization scipy


【解决方案1】:

关于您的目标函数存在一个普遍问题,它解释了为什么您获得的值彼此非常接近;下面讨论。

如果我们首先看技术方面,以下对我来说很好:

import numpy as np
from scipy.optimize import minimize


def func(Gp, Ra, Mr, Pot, Sp, Mc, Keep):
    if Keep:
        return Pot * np.tanh((Gp + Ra + Mr + Mc) * Sp)


def objective_function(x, y):

    temp = -(func(x[0], Ra=y['A']['RA'], Mr=y['A']['MR'], Pot=y['A']['POT'], Sp=y['A']['SP'], Mc=y['A']['MC'], Keep=y['A']['keep']) +
             func(x[1], Ra=y['B']['RA'], Mr=y['B']['MR'], Pot=y['B']['POT'], Sp=y['B']['SP'], Mc=y['B']['MC'], Keep=y['B']['keep']) +
             func(x[2], Ra=y['C']['RA'], Mr=y['C']['MR'], Pot=y['C']['POT'], Sp=y['C']['SP'], Mc=y['C']['MC'], Keep=y['C']['keep']))

    return temp


y = {'A': {'RA': 0.5, 'MR': 0.97, 'POT': 0.25, 'SP': 0.25, 'MC': 50., 'keep': True},
     'B': {'RA': 0.8, 'MR': 0.95, 'POT': 0.12, 'SP': 0.12, 'MC': 75., 'keep': True},
     'C': {'RA': 0.9, 'MR': 0.99, 'POT': 0.05, 'SP': 0.15, 'MC': 100., 'keep': True}}

cons = ({'type': 'ineq', 'fun': lambda x:  x[0] + x[1] + x[2] - 100.})

bnds = ((0., None), (0., None), (0., None))

print(minimize(objective_function, x0=np.array([1., 1., 1.]), args=y, method='SLSQP', bounds=bnds, constraints=cons))

这将打印出来

    fun: -0.4199999999991943
     jac: array([ 0.,  0.,  0.])
 message: 'Optimization terminated successfully.'
    nfev: 6
     nit: 1
    njev: 1
  status: 0
 success: True
       x: array([ 33.33333333,  33.33333333,  33.33333333])

如您所见,x 很好地总结为 100

如果您现在将bnds 更改为例如

bnds = ((40., 50), (0., None), (0., None))

那么结果就是

     fun: -0.419999999998207
     jac: array([ 0.,  0.,  0.])
 message: 'Optimization terminated successfully.'
    nfev: 6
     nit: 1
    njev: 1
  status: 0
 success: True
       x: array([ 40.,  30.,  30.])

再次,约束得到满足。

也可以看出,客观价值是一样的。这似乎是因为McGp 非常大,因此np.tanh 将始终只返回1.0。这意味着对于y 中的所有三个字典,您始终只从func 返回值Pot。如果把对应的三个值相加

0.25 + 0.12 + 0.05

你确实得到了0.42的值,这是由优化决定的。

【讨论】:

  • 对于这些输入:y = {'A': {'RA': 0.5, 'MR': 0.97, 'POT': 0.99, 'SP': 0.5, 'MC': 50., 'keep': True}, 'B': {'RA': 0.8, 'MR': 0.95, 'POT': 0, 'SP': 0.0000001, 'MC': 7., 'keep': True}, 'C': {'RA': 0.9, 'MR': 0.99, 'POT': 0.05, 'SP': 0.0000001, 'MC': 1., 'keep': True}} cons = ({'type': 'ineq', 'fun': lambda x: x[0] + x[1] + x[2] - 100.}) bnds = ((0., None), (0., None), (0., None)) 我得到 `x: array([ 33.33333333, 33.33333333, 33.33333333])` 这不可能是正确的,因为y['B']['POT'] 是 0,所以它应该得到 0 GP对吧?
  • @quant:这个结果完全没问题:Pot=0func 返回0;所以只有y 中的其他两个条目有助于您的目标。显然,您应用的约束不是限制性的,因此无论您将它们设置为33 还是5 都没有关系,即您不会通过将Gp 分配给贡献0 的组件来“浪费”资源。您可以通过将约束设置为10 而不是100 来轻松测试这一点;那么你的目标价值不会改变,因为你的约束没有限制。如果你进一步减少它,改变你的初始条件,使它们满足你的约束!
  • 但我想最大化这三个数量的总和。所以分配GP 做一个在任何情况下都会给0 的数量是浪费资源,因为它不会增加任何东西,对吧?这意味着如果 objective_function 将 100 GP 分配给其他两个数量而不是全部 3,则 objective_function 将具有更大的(绝对)值,不是吗?
  • @quant:不,如上所述。你的约束不是限制性的。当您将Gp 设置为100 时,您会收到与Gp=10 相同的目标值,因此如果您将资源分配给对您的目标没有贡献的组件,您不会丢失任何东西。 tanh 会很快饱和,因此 func 通常只会返回与您的输入无关的相同值。
  • 我明白了我的误解是什么。 tanh 函数的最大值在 2 左右达到,我给 y 赋予了很大的值。现在我懂了。谢谢!
猜你喜欢
  • 2014-03-13
  • 2021-06-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多