问题描述
我是 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)
你知道为什么我不能这样声明吗?