Python中具有默认值的多列表迭代

Posted

技术标签:

【中文标题】Python中具有默认值的多列表迭代【英文标题】:Multi-list iteration with default value in Python 【发布时间】:2017-06-06 19:01:43 【问题描述】:

我正在用 python 模拟进行实验,需要创建一个输入案例列表。

每个案例都是从参数列表中获取的一个实例,例如:

heights = [100,110,120]
alphas = [0.1,0.01,0.001]
C = [0.1,0.2,0.5,0.9]
B = [1,2]

列表列表是:

params = [heights,alphas,C,B]

原始数量更大(~30x100),因此直接处理每个列表效率不高。

最终每个输入案例都是每个类别的一个参数的元组/命名元组/字典,例如:

instance = 'height':100, 'alpha':0.1,'C:0.1, 'B':1

我想迭代参数空间以创建实例列表 - 但这是关键

我想迭代所有选项,而不是制作所有这些的笛卡尔积,而将其余类别设置为默认值(第一个)。例如:

params = [[1,2,3],[4,5][7,8]]

预期的实例集(没有重复)是:

[(1,4,7),(2,4,7),(3,4,7),(1,5,7)(1,4,8)]

其中 1 是第一个索引的默认值,4 是第二个索引的默认值,7 是第三个索引的默认值。

使用itertools 制作笛卡尔积非常容易:

from itertools import product
params = [[1,2,3],[4,5],[7,8]]
list(product(*params))

[(1, 4, 7), (1, 4, 8), (1, 5, 7), (1, 5, 8), (2, 4, 7), (2, 4, 8 ), (2, 5, 7), (2, 5, 8), (3, 4, 7), (3, 4, 8), (3, 5, 7), (3, 5, 8)]

然后我可以过滤掉不必要的实例,但首先生成它们听起来效率低下。有没有什么优雅的方式来构建这个迭代?

【问题讨论】:

【参考方案1】:
params = [[1, 2, 3], [4, 5], [7, 8]]
default = [par[0] for par in params]
instances = set()

for ii, pp in enumerate(params):
    for value in pp:
        new_instance = default[:ii] + [value] + default[ii + 1:]
        instances.add(tuple(new_instance))

【讨论】:

【参考方案2】:

我提出另一种方法。使用openTURNS。这个python库开发得很好,有一些类用于定义实验设计,据说在空间填充方面具有良好的特性。

请参阅此处的示例 LowDiscrepancySequence。使用此设计,您将能够进行统计分析、创建模型等。我与他们无关,但他们在该领域众所周知。

但是,如果您喜欢,您可以坚持使用您的方法。为了让它更 Pythonic,我会直接构建一个生成器表达式或列表推导:

((I, j, k) for i, j, k in product(...))

【讨论】:

【参考方案3】:

请注意,最终列表中每个元组的第 2 和第 3 个实例仅是初始数组的第 2 行和第 3 行的乘积

a, *b = params
# a = [1, 2, 3]
# b = [[4, 5], [7, 8]]

用b中的所有元素制作产品

import itertools

b = [x for x in itertools.product(*b)]
# b = [(4, 7), (4, 8), (5, 7), (5, 8)]

现在用 b 的所有值做 a 的乘积

c = [(a, b, c) for a, (b, c) in itertools.product(a, b)]

# c = [(1, 4, 7), (1, 4, 8), (1, 5, 7), (1, 5, 8), (2, 4, 7), (2, 4, 8), (2, 5, 7), (2, 5, 8), (3, 4, 7), (3, 4, 8), (3, 5, 7), (3, 5, 8)]

整体缩短:

import itertools

params = [[1,2,3],
          [4,5],
          [7,8]]

a, *b = params
f = itertools.product

c = [(a, b ,c) for a, (b, c) in f(a, f(*b))]

【讨论】:

不是还是先创建所有实例然后过滤掉吗? 我看了你写的最后一个框,认为那是你想要的输出,哦好吧哈哈。

以上是关于Python中具有默认值的多列表迭代的主要内容,如果未能解决你的问题,请参考以下文章

python 具有默认值的字典。

如何在R中的函数中有不同数量的具有默认值的参数?

groovy中具有默认值的命名参数

用python中的默认值替换高于和低于阈值的列表值?

使用Python中的* args和** kwargs验证具有默认值的参数

如果迭代器为空,Python迭代器中下一个元素的默认值?