【问题标题】:Python cartesian product and conditions?Python笛卡尔积和条件?
【发布时间】:2015-01-11 19:15:58
【问题描述】:

在 Python 中,我使用 itertools.product() 函数为模拟生成输入参数。

我有一个需要 4 个输入参数 a1、a2、b1 和 b2 的测试函数。我使用以下代码生成参数。示例:

params = itertools.product(range(10,41,2), range(10,41,2), range(0, 2), range(5, 31, 5))

... 这给了我 3072 种组合。不幸的是,某些组合在逻辑上没有意义。例如。如果 a2 大于 a1 则测试结果是无用的,同样当 b1 等于 0 时 b2 的值是完全不相关的——所以测试这样的组合是没有意义的。

除了手动操作和嵌套 for 循环之外,是否有可能限制或过滤笛卡尔积?因为我的实际用例有超过 4 个参数,这就是为什么我喜欢 itertools 的笛卡尔积函数的便利性。

有什么想法或替代方案吗? 任何帮助表示赞赏,谢谢。

【问题讨论】:

  • 如果您的用例要复杂得多,您可以查看像 numpy 这样的数组包。 (例如,这不是您想要的,但可能是相关的:stackoverflow.com/questions/25744781/…
  • itertools.product 没有过滤器参数,所以你必须自己做 - 要么编写自己的生成器,类似于 itertools.product 文档中的示例,要么过滤它 事后.

标签: python itertools


【解决方案1】:

Python 3

在 Python 3 中,您可以使用 itertools.filterfalse 过滤掉不需要的组合:

# predicate is true when need to skip the combination
predicate = (lambda (a1, a2, b1, b2): a1 <= a2 and (b1 != 0 or b2 == 5), params)
filtered_params = itertools.filterfalse(predicate, params)

Python 2

您可以使用列表理解或itertools.ifilter:

filtered_params = itertools.ifilter
    (lambda (a1, a2, b1, b2): a1 <= a2 and (b1 != 0 or b2 == 5), params)

请注意,这两个版本都会在后台循环并过滤掉。如果你想避免这种情况,你需要构建一个改进的算法来创建没有不受欢迎的元组。

【讨论】:

    【解决方案2】:

    如果您有很多参数,使用像 python-constraint 这样的模块的基于约束的方法可能更容易使用 - 让它努力找出哪些组合是有效的。

    这看起来像

    from constraint import Problem
    
    prob = Problem()
    prob.addVariables(["a1", "a2"], range(10,41,2))
    prob.addVariable("b1", [0, 2])
    prob.addVariable("b2", range(5, 31, 5))
    prob.addConstraint(lambda a1, a2: a2 <= a1, ["a1", "a2"])
    prob.addConstraint(lambda b1, b2: b1 != 0 or b2 == 5, ["b1", "b2"])
    
    for params in prob.getSolutionIter():
        run_sim(**params)
    

    【讨论】:

    • 太棒了,谢谢。我是否理解正确,这个解决方案不是首先创建一个巨大的矩阵然后减少它......而是只添加那些有意义的?!
    • @Alen:我相信它使用分支定界 - 它查看 a1 的每个值,然后查看不破坏任何约束的 a2 的每个值,等等。
    【解决方案3】:

    一种选择是让params 成为另一个生成器,它本身由itertools.product 提供。

    例如:

    params = (prod for prod in itertools.product(...) if prod[2] <= prod[1])
    

    您可以根据条件在if 之后添加任何内容。例如,prod[2] &lt;= prod[1] and prod[3] != 0 会检查您在问题中陈述的条件,只让您需要的结果通过并丢弃任何未通过测试的产品。

    【讨论】:

      【解决方案4】:

      在这种情况下,使用 numpy 的向量操作来表达您的规则可能是最方便/直观/可读的。例如:

      import numpy as np
      
      arr = np.array(list(params), dtype = [('a1',int),('a2',int),('b1',int),('b2',int)])
      arr = arr[ arr['a2'] <= arr['a1'] ]
      arr = arr[ arr['b1'] != 0 ]
      

      【讨论】:

        【解决方案5】:

        您可以结合对所选参数的任何限制来使用列表推导。我建议在执行此操作之前将您的参数放入一个集合中,以确保没有不必要的代码。在您上面提到的情况下,我不会发生这种情况,但并不总是使用range 来生成参数选项。

        例如,这里创建了一个元组参数列表,其中只有参数 1 大于参数 2 + 10 时它才是有效的组合:

        acceptableParamCombinations = 
        [ (p1,p2) for p1 in set(range(10,41,2)) for p2 in set(range(10,41,2)) if p1 > p2 + 10 ]
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-02-24
          • 2019-04-20
          • 2019-06-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-05-07
          相关资源
          最近更新 更多