简体   繁体   English

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

[英]How to extract Indexed Variable information in pyomo Model and build Pandas Dataframe

I am attempting to solve a MIP using Pyomo with several Indexed Variables of different sizes.我正在尝试使用具有多个不同大小的索引变量的 Pyomo 来解决 MIP。 What I would like to do is export the results of the variables to a dataframe so that I can further analyze these results.我想做的是将变量的结果导出到 dataframe 以便我可以进一步分析这些结果。 My problem is that I cannot figure out a way to nicely automate the process as the size of the Indexed Variables can change in each model simulation.我的问题是我无法找到一种方法来很好地自动化该过程,因为索引变量的大小可以在每个 model 模拟中发生变化。

Here is an example of some variables I would create:这是我将创建的一些变量的示例:

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()

Now, I want to create the dataframe with model.T as the index and the variable name plus the model.Generator or model.Storages as a multiIndex column (I am assuming it would have to be a multiIndex, but perhaps not). Now, I want to create the dataframe with model.T as the index and the variable name plus the model.Generator or model.Storages as a multiIndex column (I am assuming it would have to be a multiIndex, but perhaps not). A crude example of how I want it to look is shown below:我希望它看起来如何的粗略示例如下所示:

  |      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  

The values shown are just examples.显示的值只是示例。 Also, the model.T doesn't have to be the index as it would correlate to a standard index created with a dataframe.此外,model.T 不一定是索引,因为它与使用 dataframe 创建的标准索引相关。

I have been pulling my hair out trying to get this to work but I am struggling to find the right syntax in pyomo.我一直在努力让它发挥作用,但我很难在 pyomo 中找到正确的语法。 I feel there must be an easy way to extract this data as I can't be the first one trying to do this but I've searched the internet to no avail for this specific problem.我觉得必须有一种简单的方法来提取这些数据,因为我不能成为第一个尝试这样做的人,但我已经在互联网上搜索了这个特定问题无济于事。 The problem I have is trying to extract the variable index (model.T and model.Generators/Storages) from the variable results in an easy loop or vectorized fashion.我遇到的问题是尝试以简单的循环或矢量化方式从变量中提取变量索引(model.T 和 model.Generators/Storages)。

Please.请。 Any suggestions would be greatly appreciated.任何建议将不胜感激。 Let me know if I haven't made this clear enough.如果我说得不够清楚,请告诉我。

Totally doable...完全可行...

First, let's cover a basic example of how to (in the general sense) get the results out of pyomo after a solve.首先,让我们介绍一个基本示例,说明如何(在一般意义上)在求解后从pyomo中获取结果。 Recall, that after the solver completes, the optimal values of the variables will be loaded into the model variables.回想一下,求解器完成后,变量的最佳值将加载到 model 变量中。 Here is a cheap example that shows 3 ways to extract data from the variables.这是一个简单的示例,显示了从变量中提取数据的 3 种方法。 There are many others, depending on what needs to be done.还有很多其他的,取决于需要做什么。 Of note, the last method here, converting to a dictionary, is key to transitioning over to pandas because we all know pandas love dictionaries.值得注意的是,这里的最后一种方法,转换为字典,是转换到pandas的关键,因为我们都知道 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)

Yields:产量:

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

Part II:第二部分:

Ok, on to building a more comprehensive solution to your challenge of mashing the whole result into a multi-indexed dataframe.好的,继续构建一个更全面的解决方案来应对您将整个结果混合成多索引 dataframe 的挑战。 Of note, I only initialized the values of the variables in this to simulate solving.值得注意的是,我只是初始化了这个变量的值来模拟求解。 Normally, not needed for variables.通常,变量不需要。

So this builds on the concept before, which is that a pd.Series is just an array that is indexed by an index array, and can be constructed from dictionaries.所以这建立在之前的概念之上,即pd.Series只是一个由索引数组索引的数组,并且可以从字典中构造。 I'm not the slickest pandas operator, so there may be some way to combine some of the pd commands, but who cares?我不是最聪明的pandas操作员,所以可能有一些方法可以组合一些pd命令,但谁在乎呢? This is step-by-step and if you are dealing with variables from an optimization, it is not going to be too huge, so tweaking is unnecessary.这是一步一步的,如果你正在处理来自优化的变量,它不会太大,所以调整是不必要的。

# 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)

Yields产量

     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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM