Python笛卡儿的产品和条件?

时间:2015-01-11 19:15:59

标签: python itertools

在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个组合。不幸的是,某些组合在逻辑上毫无意义。 E. g。如果a2大于a1,则测试结果是无用的,当b1等于0时,b2的值完全无关 - 所以测试这样的组合是没有意义的。

是否有可能限制或过滤笛卡尔积,只需手动执行并嵌套for循环?因为我的实际用例有超过4个参数,所以我喜欢itertools中笛卡尔积函数的便利性。

任何想法或替代方案? 任何帮助表示感谢,谢谢。

5 个答案:

答案 0 :(得分:6)

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

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

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

答案 1 :(得分:2)

一个选项是让params另一个生成器,它本身来自itertools.product

例如:

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

您可以在if之后添加任何内容,具体取决于条件。例如,prod[2] <= prod[1] and prod[3] != 0将检查您在问题中陈述的条件,仅通过您需要的结果并丢弃任何未通过测试的产品。

答案 2 :(得分: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)

答案 3 :(得分:0)

您可以将列表理解与对所选参数的任何限制结合使用。我建议在执行此操作之前将参数放在一个集合中,以确保没有不必要的代码。在上面提到的情况下我不会发生,但是并不总是使用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 ]

答案 4 :(得分:0)

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

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 ]