我正在努力寻找一种有效的方法来检索优化问题的解决方案。该解决方案由大约 200K 个变量组成,我希望这些变量包含在熊猫数据帧中。在线搜索后,我发现访问变量的唯一方法是通过 for 循环,如下所示:
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)
我知道我可以使用它 for 循环将它们存储在数据帧中,但这效率很低。我发现了如何使用
import pandas as pd
index = pd.DataFrame(instance.component_objects(Var, active=True))
但我不知道如何获得解决方案
实际上有一个非常简单和优雅的解决方案,使用方法pandas.DataFrame.from_dict
与Var.extract_values()
方法相结合。
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)
收益 率
x
1 1
2 4
3 9
4 16
5 25
请注意,对于Var
我们可以同时使用 get_values()
和 extract_values()
,它们似乎也一样。对于Param
来说,只有extract_values()
.
当然,您可以使用instance.some_var.pprint()
将其打印在屏幕上。但是,如果您有一个由大型集合索引的变量。您也可以将其写入单独的文件。以下代码将结果写入.txt文件:
f = open('Result.txt', 'a')
instance.some_var.pprint(f)
f.close()
我遇到了与 Jasper 相同的问题并尝试了建议的解决方案。通过这样做,我注意到编写结果的部分需要花费大部分时间。也许在贾斯珀的案例中也是如此。
results.write()
instance.solutions.load_from(results)
因此,如果可以的话,我建议按这两行。也许有人有建议如何加快速度?或替代方法。
我还看到在这篇文章中(Pyomo:将结果保存到CSV文件(推荐了"for循环"方法。一位 pyomo 开发人员说:"我认为在选项 2 中,索引和变量切片可以以不同的顺序迭代,这将使生成的数组无效。
为了代码的简单性和在很大程度上避免 for 循环,我在 urbs 项目中找到了 pyomoio
模块,它接管了略微弃用的 pandaspyomo.py 代码。它依赖于每个 pyomo 对象的iteritem()
方法,并优雅地处理多个维度。它可以提取集合,参数,变量作为熊猫对象。
如果我设置了一个小型 pyomo 模型
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)
我只需一行代码即可读取参数
%%timeit
a_po = po.get_entity(m, 'a')
# 110 ms ± 1.88 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
但是,如果我将其与原始问题中的方法进行比较,它并不快,甚至慢一点:
%%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)