优化python中的非线性函数

时间:2018-01-17 12:17:44

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

我在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

所有 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

1 个答案:

答案 0 :(得分:1)

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

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

'use strict';

process.env.DEBUG = 'actions-on-google:*';

const ActionsSdkApp = require('actions-on-google').ActionsSdkApp;
const functions = require('firebase-functions');

const NO_INPUTS = [
    'Padon me, I didn\'t hear that.',
    'If you\'re still there, would you please say that again.',
    'We can stop here. Good luck with your shopping.'
];

const SHOPPING_INTENT = 'SHOPPING';

exports.shopStrollers = functions.https.onRequest((request, response) => {
    const app = new ActionsSdkApp({request, response});


    function handleMainInput(app) {
        console.log('mainIntent is invoked!');
        console.log("The input is %s", app.getRawInput());
        console.log("It seems that %s is never invoked!", app.StandardIntents.TEXT)

        let inputPrompt = app.buildInputPrompt(true, '<speak>Hi! <break time="1"/> ' +
            'I can help with finding strollers. How old is your baby?</speak>', NO_INPUTS);
        app.ask(inputPrompt);
    }

    function handleTextInput(app) {
        console.log('TEXT is invoked!');
        console.log("The input is %s", app.getRawInput());
        console.log("Finally TEXT HANDLER got invoked")

        if (app.getRawInput() === 'bye') {
            app.tell('Hope you found the service helpful and best of luck with your shopping, please come back again, goodbye!');
        } else {
            let inputPrompt = app.buildInputPrompt(true, '<speak>Here is a list of top' +
                ' <say-as interpret-as="ordinal">10</say-as>strollers' +
                ', say next for the next batch</speak>', NO_INPUTS);
            app.ask(inputPrompt);
        }
    }


    let actionMap = new Map();
    actionMap.set(SHOPPING_INTENT, handleTextInput);
    actionMap.set(app.StandardIntents.MAIN, handleMainInput);
    actionMap.set(app.StandardIntents.TEXT, handleTextInput);

    app.handleRequest(actionMap);
});

这将打印

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.]) Mc非常大,因此Gp将始终只返回np.tanh。这意味着您始终只会在1.0中为Pot中的所有三个词典返回值func。如果总结三个相应的值

y

确实得到了由优化确定的值0.25 + 0.12 + 0.05