【问题标题】:Multi-list iteration with default value in PythonPython中具有默认值的多列表迭代
【发布时间】: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)]

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

【问题讨论】:

    标签: python iterator itertools


    【解决方案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))]
        

        【讨论】:

        • 不是还是先创建所有实例然后过滤掉吗?
        • 我看了你写的最后一个框,认为那是你想要的输出,哦好吧哈哈。
        猜你喜欢
        • 2021-07-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-09-16
        • 2012-05-12
        • 1970-01-01
        • 1970-01-01
        • 2013-08-11
        相关资源
        最近更新 更多