Pyomo DataPortal 不适用于多个索引(抽象模型,CSV 导入)

Pyomo DataPortal Not Working with Multiple Indices (Abstract Model, CSV Import)

我正在尝试使用 Pyomo 中的 DataPortal 设置为抽象模型导入 CSV 数据。

from pyomo.environ import *
model = AbstractModel()
model.t = Set()  # year index
model.a = Set()  # type of resource index
model.q = Set()  # zone index
model.EERF = Param(model.a, model.q, model.t)  # feedstock production

data = DataPortal()
data.load(filename='EERBiomassProd.csv', param=model.EERF, index=(model.t, model.q, model.a))
instance = model.create_instance(data)

我从中导入的 CSV 有四列和很多行。

year zone source tons
2020 california herbaceous 2
2020 california waste 4
... ... ... ...
2050 utah/nevada woody 900

一共有4年的数值,10个区域,3个来源。我希望这些都是我的参数的索引,参数的值设置为“tons”列。

当我 运行 我的代码时,我从 Python 收到以下错误。

RuntimeError: Failed to set value for param=EERF, index=(2020, 'california', 'herbaceous'), value=2.
    source error message=unsupported operand type(s) for +: 'int' and 'type'

建议?我可以尝试以其他方式导入数据,比如使用 Pandas 数据框吗?我是否应该手动写出每个索引是什么,而不是尝试使用 DataPortal(例如 model.t = Set(initialize=[2020, 2030, 2040, 2050]))从 CSV 中读取它们?

我觉得你是在找麻烦...:)

你 运行 通过读取这样的数据遇到的问题是从多维集到单个集的推理。我不认为 pyomo 可以自然地做到这一点。您或许可以从 3-dim 索引中折磨出各个集合,但可能不值得。您将遇到 pyomo 必须解决的重复问题等。指数中可能有很多重复项(2020 年将出现多次,加利福尼亚等地也一样)。

下面的第一个示例读取您的数据(使用下面发布的类似 .csv),但仅捕获 3-dim 索引。也许这“足够好”但不太可能。

如果你想留在“抽象领域”,你应该将你的集合分解成单独的数据 fields/files 等等,也许在文档中使用 JSON 或 YAML 结构。

选项 2 是使用 csv readerpandas 或自行开发的东西来读取 pyomo 之外的数据,然后根据结果制作一个 ConcreteModel。这是示例中的 m2。我认为这是最简单的?取决于您模型的其余部分...

data.csv:

year,zone,source,tons
2020,ca,herb,2
2020,ca,waste,3
2020,nv,waste,4
2019,az,herb,5

脚本:

from pyomo.environ import *
model = AbstractModel()
# model.t = Set()  # year index
# model.a = Set()  # type of resource index
# model.q = Set()  # zone index

model.tqa = Set(dimen=3)
model.EERF = Param(model.tqa)  # feedstock production

data = DataPortal()
data.load(filename='data.csv', param=model.EERF, index=model.tqa)
instance = model.create_instance(data)
instance.pprint()

###  Option 2 ###

import pandas as pd

df = pd.read_csv('data.csv').set_index(['year', 'zone', 'source'])
model_data = df.to_dict('index')

m2 = ConcreteModel('pandas_based')

### SETS
# note:  sorted lists from sets is required to (1) avoid dupes,
#        and (2) provide lists to initializer for consistent
#        (deterministic) results.  Failure to do either will gen warnings...
m2.t = Set(initialize=sorted({t[0] for t in model_data.keys()}))
m2.q = Set(initialize=sorted({t[1] for t in model_data.keys()}))
m2.a = Set(initialize=sorted({t[2] for t in model_data.keys()}))

# a convenience for later use...
m2.tqa_idx = Set(within=m2.t*m2.q*m2.a, initialize=model_data.keys())

### PARAMS
m2.EERF = Param(m2.t, m2.q, m2.a, initialize=
    {t[0]:t[1]['tons'] for t in model_data.items()})

print(' *** Concrete Model *** ')
m2.pprint()

输出:

1 Set Declarations
    tqa : Size=1, Index=None, Ordered=Insertion
        Key  : Dimen : Domain : Size : Members
        None :     3 :    Any :    4 : {(2020, 'ca', 'herb'), (2020, 'ca', 'waste'), (2020, 'nv', 'waste'), (2019, 'az', 'herb')}

1 Param Declarations
    EERF : Size=4, Index=tqa, Domain=Any, Default=None, Mutable=False
        Key                   : Value
         (2019, 'az', 'herb') :     5
         (2020, 'ca', 'herb') :     2
        (2020, 'ca', 'waste') :     3
        (2020, 'nv', 'waste') :     4

2 Declarations: tqa EERF
 *** Concrete Model *** 
7 Set Declarations
    EERF_index : Size=1, Index=None, Ordered=True
        Key  : Dimen : Domain : Size : Members
        None :     3 :  t*q*a :   12 : {(2019, 'az', 'herb'), (2019, 'az', 'waste'), (2019, 'ca', 'herb'), (2019, 'ca', 'waste'), (2019, 'nv', 'herb'), (2019, 'nv', 'waste'), (2020, 'az', 'herb'), (2020, 'az', 'waste'), (2020, 'ca', 'herb'), (2020, 'ca', 'waste'), (2020, 'nv', 'herb'), (2020, 'nv', 'waste')}
    a : Size=1, Index=None, Ordered=Insertion
        Key  : Dimen : Domain : Size : Members
        None :     1 :    Any :    2 : {'herb', 'waste'}
    q : Size=1, Index=None, Ordered=Insertion
        Key  : Dimen : Domain : Size : Members
        None :     1 :    Any :    3 : {'az', 'ca', 'nv'}
    t : Size=1, Index=None, Ordered=Insertion
        Key  : Dimen : Domain : Size : Members
        None :     1 :    Any :    2 : {2019, 2020}
    tqa_idx : Size=1, Index=None, Ordered=Insertion
        Key  : Dimen : Domain         : Size : Members
        None :     3 : tqa_idx_domain :    4 : {(2020, 'ca', 'herb'), (2020, 'ca', 'waste'), (2020, 'nv', 'waste'), (2019, 'az', 'herb')}
    tqa_idx_domain : Size=1, Index=None, Ordered=True
        Key  : Dimen : Domain                   : Size : Members
        None :     3 : tqa_idx_domain_index_0*a :   12 : {(2019, 'az', 'herb'), (2019, 'az', 'waste'), (2019, 'ca', 'herb'), (2019, 'ca', 'waste'), (2019, 'nv', 'herb'), (2019, 'nv', 'waste'), (2020, 'az', 'herb'), (2020, 'az', 'waste'), (2020, 'ca', 'herb'), (2020, 'ca', 'waste'), (2020, 'nv', 'herb'), (2020, 'nv', 'waste')}
    tqa_idx_domain_index_0 : Size=1, Index=None, Ordered=True
        Key  : Dimen : Domain : Size : Members
        None :     2 :    t*q :    6 : {(2019, 'az'), (2019, 'ca'), (2019, 'nv'), (2020, 'az'), (2020, 'ca'), (2020, 'nv')}

1 Param Declarations
    EERF : Size=4, Index=EERF_index, Domain=Any, Default=None, Mutable=False
        Key                   : Value
         (2019, 'az', 'herb') :     5
         (2020, 'ca', 'herb') :     2
        (2020, 'ca', 'waste') :     3
        (2020, 'nv', 'waste') :     4