Retrieving Pyomo solution without using for loop

亡梦爱人 提交于 2020-01-04 00:10:12

问题


I am struggling to find an efficient way of retrieving the solution to an optimization problem. The solution consists of around 200K variables that I would like in a pandas DataFrame. After searching online the only approaches I found for accessing the variables was through a for loop which looks something like this:

instance = M.create_instance('input.dat') # reading in a datafile
results = opt.solve(instance, tee=True)
results.write()
instance.solutions.load_from(results)

for v in instance.component_objects(Var, active=True): 
    print ("Variable",v)
    varobject = getattr(instance, str(v))
    for index in varobject:
        print ("   ",index, varobject[index].value)

I know I can use this for loop to store them in a dataframe but this is pretty inefficient. I found out how to access the indexes by using

import pandas as pd
index = pd.DataFrame(instance.component_objects(Var, active=True))

But I dont know how to get the solution


回答1:


There is actually a very simple and elegant solution, using the method pandas.DataFrame.from_dict combined with the Var.extract_values() method.

from pyomo.environ import *
import pandas as pd
m = ConcreteModel()
m.N = RangeSet(5)
m.x = Var(m.N, rule=lambda _, el: el**2)  # x = [1,4,9,16,25]

df = pd.DataFrame.from_dict(m.x.extract_values(), orient='index', columns=[str(m.x)])
print(df)

yields

    x
1   1
2   4
3   9
4  16
5  25

Note that for Var we can use both get_values() and extract_values(), they seem to do the same. For Param there is only extract_values().




回答2:


Of course you can use instance.some_var.pprint() to print it on the screen. But if you have a variable indexed by a large set. You can also write it to a seperate file. The following code writes the result to a .txt file:

f = open('Result.txt', 'a')
instance.some_var.pprint(f)
f.close()



回答3:


For simplicity of code and to largely avoid for-loops, I found the pyomoio module in the urbs project, which has taken over the slightly deprecated code of pandaspyomo.py. It relies on each pyomo object's iteritem() method, and handles multiple dimensions elegantly. It can extract sets, parameters, variables as pandas objects.

If I set up a small pyomo model

from pyomo.environ import *
import pyomoio as po
import pandas as pd

# Define a model with 200k values
m = ConcreteModel()
m.ix = RangeSet(200000)
def idem(model, i):
    return i
m.a = Param(m.ix, rule=idem)

I can read in the parameter with just one line of code

%%timeit
a_po = po.get_entity(m, 'a')

# 110 ms ± 1.88 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

However, if I compare it to the approach in the original question, it is not faster, even a little slower:

%%timeit
val = []
ix = []
varobject = getattr(m, 'a')
for index in varobject:
    ix.append(index)
    val.append(varobject[index])
a = pd.Series(index=ix, data=val)
# 92.5 ms ± 1.57 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)



回答4:


I had the same issue as Jasper and tried the suggested solutions. By doing so I noticed, that the part writing the results takes most time. Maybe this is also true in Jasper's case.

results.write()
instance.solutions.load_from(results)

So I suggest to surpress this two lines if you can do so. Maybe someone has a suggestions how to speed this up? Or an alternative method.

Also I saw that in this post (Pyomo: Save results to CSV files) The "for loop" method is recomanded. A pyomo developer states:"I think it's possible in option 2 for the indices and the variable slice to be iterated over in a different order which would invalidate your resulting array."



来源:https://stackoverflow.com/questions/48475419/retrieving-pyomo-solution-without-using-for-loop

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!