Определить параметр в pyomo из 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)
...

Аргумент "требование" в функции - это фрейм данных pandas.

Функция 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 и 0, если шина не находится в DataFrame. РЕДАКТИРОВАТЬ: определяется вне функции define_problem.

Но это не работает. Как я могу определить параметры моей функции из фрейма данных pandas?

РЕДАКТИРОВАТЬ: Спасибо за ответы!

Фрейм данных спроса выглядит так:

      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]

«T» и «шина», которые должны попасть в функцию require_init, - это числа в индексе и имена столбцов во фрейме данных. Они находятся в наборах model.SET_HOURS и model.SET_BUSES соответственно.


person CamiloMagnere    schedule 06.02.2019    source источник
comment
Добро пожаловать в SO! Не могли бы вы привести пример того, что содержат несколько строк вашего фрейма данных? Также может быть полезно знать, какие значения для bus и t передаются вашей demand_init функции. Наконец, вам может быть полезно просмотреть этот пост, в котором описывается как создать минимальный, полный и проверяемый пример.   -  person James Dellinger    schedule 07.02.2019
comment
Кроме того, где определяется ваш require_init? rule не будет передавать функции дополнительные аргументы. Было бы разумнее определить ваш запрос require_init в define_problem   -  person Qi Chen    schedule 07.02.2019
comment
Привет! Только что отредактировал, отвечая на ваши вопросы. Я попробую определить функцию require_init внутри функции define_problem.   -  person CamiloMagnere    schedule 07.02.2019


Ответы (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 может помочь значительно сократить усилия, затрачиваемые на ручной ввод данных.

person Giorgio Balestrieri    schedule 15.02.2019
comment
что делать, если параметры более 2-х мерные? - person janicebaratheon; 01.04.2020
comment
@janicebaratheon отличный вопрос. Наилучший формат - использовать аккуратный формат, т.е. только одно значение. в строке. Допустим, у вас есть сценарий третьего измерения, у вас будет четыре столбца в DataFrame: ["scenario", "bus", "hour", "value"]. Вы можете преобразовать в словарь следующим образом: df.set_index(["scenario", "bus", "hour"]).squeeze().to_dict() (squeeze преобразует его в Series). Примечательно, что это работает с любым количеством измерений. - person Giorgio Balestrieri; 04.04.2020

Я изменил свой подход и решил его.

Вы можете передать словарь в функцию Param, поэтому я изменил функцию require_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)

И часы, и автобусы должны быть определены заранее.

Я надеюсь, что это помогает кому-то.

person CamiloMagnere    schedule 08.02.2019