从pandas DataFrame在pyomo中定义参数

时间:2019-02-06 20:07:33

标签: python python-3.x pandas optimization pyomo

第一次使用pyomo用户。

我有一个定义模型的函数

def define_problem(SET_gen, SET_time, SET_buses, demand):                       

    model = pyo.ConcreteModel()

    #Define sets
    model.SET_GEN   = pyo.Set(initialize = SET_gen) #Set of generators
    model.SET_TIME = pyo.Set(initialize = SET_time) #Set of hours
    model.SET_BUSES = pyo.Set(initialize = SET_buses)   #Set of buses

    #Define parameters
    model.DEMAND = pyo.Param(model.SET_BUSES, model.SET_TIME, initialize = demand_init)
...

函数中的参数'demand'是熊猫DataFrame

demand_init函数定义如下

def demand_init(model, bus, t, data = demand):
    if(bus in set(data.columns)):
        return data.loc[t,bus]
    return 0.0

应将每小时和每条总线的参数模型.DEMAND定义为需求DataFrame中的相应“单元”,如果总线不在DataFrame中,则将其定义为0。 编辑:在define_problem函数外部定义。

但是它不起作用。如何从pandas DataFrame定义函数的参数?

  

编辑:谢谢您的回答!

需求数据框如下所示:

      Bus1  Bus10  Bus11  Bus12  ...     Bus6  Bus7  Bus8   Bus9
Hour                             ...                            
1      0.0   9.00   3.50   6.10  ...    11.20   0.0   0.0  29.50
2      0.0   7.34   2.85   4.97  ...     9.13   0.0   0.0  24.06
3      0.0   6.45   2.51   4.37  ...     8.03   0.0   0.0  21.14
4      0.0   5.78   2.25   3.92  ...     7.20   0.0   0.0  18.95
5      0.0   5.56   2.16   3.77  ...     6.92   0.0   0.0  18.22

[5 rows x 14 columns]

应该进入demand_init函数的't'和'bus'是索引中的数字和数据帧中的列的名称。它们分别位于模型model.SET_HOURS和model.SET_BUSES中。

2 个答案:

答案 0 :(得分:0)

我改变了方法并解决了。

您可以将字典传递给Param函数,因此我将demand_init函数更改为以下内容:

def demand_init(model, data):
    init = {}
    for t in model.SET_HOURS:
        for bus in model.SET_BUSES:
            if(bus in set(data.columns)):
                init[bus,t] = data.loc[t,bus]
            else:
                init[bus,t] = 0
    return init

然后,我像这样定义参数:

INIT_demand  = demand_init(model, data = demand)
model.DEMAND = pyo.Param(model.SET_BUSES, model.SET_HOURS, initialize = INIT_demand)

小时设置和公交设置都必须预先定义。

我希望这对某人有帮助。

答案 1 :(得分:0)

您似乎已经涵盖了这一点,所以我只提供一些建议:

仅调用第1,2列等,然后调用 axis bus,而不是调用每列"Bus1"等,将使您的生活变得更加轻松。

from pyomo import environ as pye
import pandas as pd
import numpy as np
​
n_bus = 5
n_hours = 10
​
demand_df = pd.DataFrame(
    data = np.random.random(size=(n_hours, n_bus)),
    columns = np.arange(1, n_bus+1), 
    index = np.arange(1, n_hours+1))
​
demand_df = demand_df.rename_axis('hour', axis=0)
demand_df = demand_df.rename_axis('bus', axis=1)

现在DataFrame看起来像

>>> demand_df.head()
bus 1           2           3           4           5
hour                    
1   0.249303    0.244917    0.348141    0.559970    0.414997
2   0.803017    0.940600    0.474955    0.976134    0.185487
3   0.776821    0.940770    0.482725    0.510914    0.186607
4   0.705604    0.871578    0.154195    0.943887    0.913865
5   0.039853    0.978370    0.320563    0.923042    0.591475

一种简单的获取字典{(hour,bus):value}的方法是:

demand_d = demand_df.stack().to_dict()

现在,您似乎想将0定义为默认值。三种方法(从最坏到最好,恕我直言):

  • 使用defaultdict
from collections import defaultdict
demand_d =defaultdict(int, demand_df.stack().to_dict())
  • 确保所有列均填充0(.fillna(0)
  • 定义参数的默认值
model.DEMAND = pyo.Param(
    model.SET_BUSES, model.SET_HOURS, 
    initialize = demand_d,
    default = 0)

最后要注意的是,AbstractModel可能有助于大大减少手动数据提取的工作量。