从 pandas DataFrame 在 pyomo 中定义参数

Define parameter in pyomo from pandas DataFrame

第一次使用 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'是一个pandasDataFrame

函数demand_init定义如下

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

需要为每个小时和每辆公交车定义参数model.DEMAND作为需求DataFrame中对应的'cell',如果公交车不在DataFrame中则为0。 编辑: 在 define_problem 函数外定义。

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

EDIT: Thanks for the answers!

需求数据框如下所示:

      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 中。

我改了方法解决了

您可以将字典传递给 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,2 等并调用 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 可能有助于大大减少手动数据摄取的工作量。