Pyomo 优化投资/收入 产量:

问题描述

我是 Pyomo 的新手,我正在尝试根据预算优化投资。
我有一个总预算,我想找到在不同媒体上分配预算的最佳方式。
例如:total_budget = 5000 --> tv = 3000,cinema = 500,radio = 1500。

我正在努力将预算与相应的收入“联系起来”。 媒体有不同的回报曲线(最好先投资一个特定的媒体,直到达到一定的预算,然后再投资其他媒体)。
不同媒体的收入由如下函数返回:tv_1k_revenue = calculate_revenue(budget=1000,media="tv")
假设我唯一的限制是简化问题的总预算(我认为我可以管理其他限制)。

这是我目前的代码

model = pyo.ConcreteModel(doc="Optimization model")

# Declaration of possible budgets
model.S1 = Set(initialize=[*df.TV_Budget.values])
model.tv_budget = Var(model.S1,initialize=0.0)
model.S2 = Set(initialize=[*df.Cinema_Budget.values])
model.cinema_budget = Var(model.S2,initialize=0.0)
model.S3 = Set(initialize=[*df.Radio_Budget.values])
model.radio_budget = Var(model.S3,initialize=0.0)

# Objective function
def func_objective(model):
    objective_expr = sum(model.tv_revenue +
                         model.cinema_revenue +
                         model.radio_revenue)
return objective_expr

model.objective = pyo.Objective(rule=func_objective,sense=pyo.maximize)

所以我的问题是,我如何声明 model.tv_revenue、model.cinema_revenue、model.radio_revenue 以便我可以优化电视、电影和广播预算,以最大化电视、电影和广播产生的总收入? 现在我为每个媒体创建了一个带有预算和收入列的 DataFrame,但最好的方法应该是使用我的 calculate_revenue 函数并为每个媒体预算设置 bounds=(min_budget,max_budget)

感谢您的帮助!

解决方法

根据您提供的信息以及您对 pyomo 的有限经验,这是我的建议...

您似乎有预算和收入,而且这些似乎被索引按媒体类型。目前尚不清楚您现在对索引做什么。所以我希望是这样的:

model.medias = pyo.Set(initialize=['radio','tv',... ])

model.budget = pyo.Var(model.medias,domain=pyo.NonNegativeReals)
...

pandas 扔出窗外。这是一个很棒的包,但对设置模型没有帮助。尝试仅使用 python 字典来保存常量和参数。 (如果这令人困惑,请参阅我的其他一些示例)。

我敢打赌,您最终会遇到的问题是您的收入函数可能是非线性的。对?我将从它的一个简单的线性近似开始,看看您是否可以使该模型工作,然后考虑进行分段线性近似或使用某种非线性求解器。

==================== 编辑/附加信息。

关于 obj 函数,您不能只是填充对返回值的非线性函数的引用。目标必须是有效的 pyomo 表达式(线性或非线性),由模型元素组成。我会从这样的事情开始......

# media mix

import pyomo.environ as pyo

# data for linear approximations of form revenue = c1 * budget + c0

#           media      c0  c1
consts = {  'radio' : (4,0.6),'tv'    : (12,0.45)}

# a bunch of other parameters....??  limits,minimums,etc.


### MODEL

m = pyo.ConcreteModel('media mix')

### SETS
m.medias = pyo.Set(initialize=consts.keys())


### VARIABLES
m.budget = pyo.Var(m.medias,domain=pyo.NonNegativeReals)


### OBJ
m.obj = pyo.Objective(expr=sum(consts[media][1]*m.budget[media] + consts[media][0] for media in m.medias),sense=pyo.maximize)

m.pprint()

产量:

1 Set Declarations
    medias : Size=1,Index=None,Ordered=Insertion
        Key  : Dimen : Domain : Size : Members
        None :     1 :    Any :    2 : {'radio','tv'}

1 Var Declarations
    budget : Size=2,Index=medias
        Key   : Lower : Value : Upper : Fixed : Stale : Domain
        radio :     0 :  None :  None : False :  True : NonNegativeReals
           tv :     0 :  None :  None : False :  True : NonNegativeReals

1 Objective Declarations
    obj : Size=1,Active=True
        Key  : Active : Sense    : Expression
        None :   True : maximize : 0.6*budget[radio] + 4 + 0.45*budget[tv] + 12

3 Declarations: medias budget obj
,

非常感谢@AirSquid!
就是这样。
在我的情况下扔熊猫确实很有意义。
另外,是的,我的收入函数是非线性的。
我可能会尝试进行线性近似,看看我是否可以做到这一点。 我打算尝试将我的目标函数声明为:

def func_objective(model):
    objective_expr = sum([calculate_revenue(model.budget[media],media=media) for media in model.medias])
return objective_expr
model.objective = pyo.Objective(rule=func_objective,sense=pyo.maximize)

你知道为什么我不能这样声明吗?