如何在 pyomo 模型中提取索引变量信息并构建 Pandas Dataframe

Cor*_*can 5 python variables multi-index pandas pyomo

我正在尝试使用 Pyomo 和多个不同大小的索引变量来解决 MIP。我想做的是将变量的结果导出到数据框,以便我可以进一步分析这些结果。我的问题是,我无法找到一种方法来很好地自动化该过程,因为索引变量的大小在每个模型模拟中都可能发生变化。

这是我将创建的一些变量的示例:

import pyomo.environ as pyo

model = pyo.ConcreteModel()

model.T = pyo.RangeSet(0, 10)
model.Generators = pyo.Set(initialize=(['equip_1', 'equip_2']))
model.Storages = pyo.Set(initialize=(['storage_1', 'storage_2']))

model.var_1 = pyo.Var(model.T, model.Generators, domain=pyo.NonNegativeReals)
model.var_2 = pyo.Var(model.T, domain=pyo.NonNegativeReals)
model.var_3 = pyo.Var(model.T, model.Storages, domain=pyo.NonNegativeReals)
model.var_4 = pyo.Var(model.T, model.Generators, domain=pyo.Binary, initialize=0)

# constraints and objective function here, which I don't think are relevant for the question
.
.
.
SolverFactory('cbc').solve(model).write()
Run Code Online (Sandbox Code Playgroud)

现在,我想创建以 model.T 作为索引、变量名称加上 model.Generator 或 model.Storages 作为 multiIndex 列的数据框(我假设它必须是 multiIndex,但也许不是)。我希望它的外观的粗略示例如下所示:

  |      Var_1      | Var_2 |        Var_3        |      Var_4
  | equip_1 equip_2 | None  | storage_1 storage_2 | equip_1 equip_2
m |   0    |   0    |   0   |     0     |   0     |   0    |   1  
o |   1    |   1    |   1   |     1     |   1     |   1    |   0  
d |   2    |   2    |   2   |     2     |   2     |   0    |   1  
e |   3    |   3    |   3   |     3     |   3     |   1    |   0  
l |   4    |   4    |   4   |     4     |   4     |   0    |   1  
. |   5    |   5    |   5   |     5     |   5     |   1    |   0  
T |   6    |   6    |   6   |     6     |   6     |   0    |   1  
Run Code Online (Sandbox Code Playgroud)

显示的值只是示例。此外, model.T 不一定是索引,因为它与使用数据帧创建的标准索引相关。

我一直在努力让它工作,但我正在努力在 pyomo 中找到正确的语法。我觉得必须有一种简单的方法来提取这些数据,因为我不可能是第一个尝试这样做的人,但我在互联网上搜索过这个特定问题却无济于事。我遇到的问题是尝试以简单的循环或矢量化方式从变量结果中提取变量索引(model.T 和 model.Generators/Storages)。

请!任何建议将不胜感激。如果我说得不够清楚,请告诉我。

Air*_*uid 7

完全可行...

pyomo首先,让我们介绍一个基本示例,说明如何(一般意义上)在求解后获得结果。回想一下,求解器完成后,变量的最优值将被加载到模型变量中。这是一个简单的示例,展示了从变量中提取数据的 3 种方法。还有很多其他的,取决于需要做什么。值得注意的是,这里的最后一个方法,转换为字典,是转换的关键,pandas因为我们都知道熊猫喜欢字典。

# extracting values 1
import pyomo.environ as pyo
import pandas as pd

m = pyo.ConcreteModel('value extraction')

m.S = pyo.Set(initialize=range(3))
m.X = pyo.Var(m.S, initialize={0:-1, 1:2.5, 2:12})   # just initializing to simulate solving

# show all of X
m.X.display()

# iterate through and show values
print()
for s in m.S:
    print(f'for index {s} X[{s}] is: {m.X[s].value}')

# dump into a dictionary.... an entry point for pandas!
print()
print(m.X.extract_values())

# make a pd.Series indexed by the index set(s)
print()
x_vals = pd.Series(m.X.extract_values(), name=m.X.name)
print(x_vals)
Run Code Online (Sandbox Code Playgroud)

产量:

X : Size=3, Index=S
    Key : Lower : Value : Upper : Fixed : Stale : Domain
      0 :  None :    -1 :  None : False : False :  Reals
      1 :  None :   2.5 :  None : False : False :  Reals
      2 :  None :    12 :  None : False : False :  Reals

for index 0 X[0] is: -1
for index 1 X[1] is: 2.5
for index 2 X[2] is: 12

{0: -1, 1: 2.5, 2: 12}

0    -1.0
1     2.5
2    12.0
Name: X, dtype: float64
Run Code Online (Sandbox Code Playgroud)

第二部分:

好的,接下来构建一个更全面的解决方案来应对将整个结果混合到多索引数据帧中的挑战。值得注意的是,我只是初始化了其中变量的值来模拟求解。通常,不需要变量。

所以这建立在之前的概念之上,即 apd.Series只是一个由索引数组索引的数组,并且可以从字典构造。我不是最熟练的pandas操作员,因此可能有某种方法可以组合某些pd命令,但谁在乎呢?这是一步一步的,如果您正在处理优化中的变量,它不会太大,因此没有必要进行调整。

# extracting values 2
import pyomo.environ as pyo
import pandas as pd

model = pyo.ConcreteModel()

model.T = pyo.RangeSet(0, 10)
model.Generators = pyo.Set(initialize=(['equip_1', 'equip_2']))
model.Storages = pyo.Set(initialize=(['storage_1', 'storage_2']))

model.var_1 = pyo.Var(model.T, model.Generators, initialize=1.5, domain=pyo.NonNegativeReals)
model.var_2 = pyo.Var(model.T, initialize=2.5, domain=pyo.NonNegativeReals)
model.var_3 = pyo.Var(model.T, model.Storages, initialize=3.5, domain=pyo.NonNegativeReals)
model.var_4 = pyo.Var(model.T, model.Generators, domain=pyo.Binary, initialize=0)

#model.display()

# let's convert each var to a pandas series, indexed by model.T...

# get all the variables (assuming the fuller model will have constraints, params, etc.)
model_vars = model.component_map(ctype=pyo.Var)


serieses = []   # collection to hold the converted "serieses"
for k in model_vars.keys():   # this is a map of {name:pyo.Var}
    v = model_vars[k]

    # make a pd.Series from each    
    s = pd.Series(v.extract_values(), index=v.extract_values().keys())

    # if the series is multi-indexed we need to unstack it...
    if type(s.index[0]) == tuple:  # it is multi-indexed
        s = s.unstack(level=1)
    else:
        s = pd.DataFrame(s)         # force transition from Series -> df
    #print(s)

    # multi-index the columns
    s.columns = pd.MultiIndex.from_tuples([(k, t) for t in s.columns])

    serieses.append(s)

df = pd.concat(serieses, axis=1)
print(df)
Run Code Online (Sandbox Code Playgroud)

产量

     var_1         var_2     var_3             var_4        
   equip_1 equip_2     0 storage_1 storage_2 equip_1 equip_2
0      1.5     1.5   2.5       3.5       3.5       0       0
1      1.5     1.5   2.5       3.5       3.5       0       0
2      1.5     1.5   2.5       3.5       3.5       0       0
3      1.5     1.5   2.5       3.5       3.5       0       0
4      1.5     1.5   2.5       3.5       3.5       0       0
5      1.5     1.5   2.5       3.5       3.5       0       0
6      1.5     1.5   2.5       3.5       3.5       0       0
7      1.5     1.5   2.5       3.5       3.5       0       0
8      1.5     1.5   2.5       3.5       3.5       0       0
9      1.5     1.5   2.5       3.5       3.5       0       0
10     1.5     1.5   2.5       3.5       3.5       0       0
Run Code Online (Sandbox Code Playgroud)