从 pandas DataFrame 在 pyomo 中定义参数

Posted

技术标签:

【中文标题】从 pandas DataFrame 在 pyomo 中定义参数【英文标题】:Define parameter in pyomo from pandas DataFrame 【发布时间】:2019-06-30 21:13:41 【问题描述】:

这里是第一次 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'是一个pandas 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

它应该将每个小时和每条总线的参数model.DEMAND定义为需求DataFrame中对应的'cell',如果总线不在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 中。

【问题讨论】:

欢迎来到 SO!您能否提供一个示例,说明您的数据框的几行包含什么?了解 bust 的哪些值正在传递给您的 demand_init 函数也可能会有所帮助。最后,您可能会发现查看这篇描述 how to create a Minimal, Complete, and Verifiable example 的帖子会有所帮助。 另外,你的 demand_init 是在哪里定义的? rule 不会向函数传递额外的参数。在 define_problem 中定义你的 demand_init 会更有意义 嗨!刚刚做了一些编辑回答你的问题。我将尝试在 define_problem 函数中定义 demand_init 函数。 【参考方案1】:

我改变了我的方法并解决了它。

你可以将字典传递给 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)

必须预先定义 Hours 集和 Buses 集。

我希望这对某人有所帮助。

【讨论】:

【参考方案2】:

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

只需调用列 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 可能有助于大大减少手动数据提取的工作量。

【讨论】:

参数超过二维怎么办? @janicebaratheon 好问题。最好的格式是使用tidy format,即每行只有一个值。假设您有一个第三维“场景”,您将在DataFrame 中有四列:["scenario", "bus", "hour", "value"]。您可以按如下方式转换为字典:df.set_index(["scenario", "bus", "hour"]).squeeze().to_dict()squeeze 将其转换为 Series)。值得注意的是,这适用于任意数量的维度。

以上是关于从 pandas DataFrame 在 pyomo 中定义参数的主要内容,如果未能解决你的问题,请参考以下文章

pandas从dataframe中删除一个或多个数据列

从 pandas DataFrame 制作热图

Pandas:从 DataFrame 分配 MultiIndex 列

从 pandas.DataFrame 中选择复杂的标准

从 Pandas DataFrame 中删除一列

从 pandas 返回多个值适用于 DataFrame