Python cartesian product and conditions?

China☆狼群 提交于 2019-12-05 18:55:58

If you have many parameters, a constraint-based approach using a module like python-constraint may be easier to work with - let it do the hard work of figuring out which combinations are valid.

This would look something like

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)

You can use list comprehension or itertools.ifilter:

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

Note that both of these versions loop and filter out under the hood. If you want to avoid that, you'll need to construct an improved algorithm that creates the tuples without the undesirables.

One option is to make params another generator which itself is fed from itertools.product.

For example:

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

You could add anything after the if depending on what conditions are. For instance prod[2] <= prod[1] and prod[3] != 0 would check for the conditions you state in your question, letting through only the results that you need and discarding any products which failed the tests.

In cases such as this, it can be most convenient/intuitive/readable to express your rules using numpy's vector operations. 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 ]

You can use list comprehension in combination with any restrictions on the parameters you choose. I recommend putting your parameters in a set before doing this, to make sure there is no unnecessary code. I wouldn't happen in the case you mention above, but one does not always use range to generate parameter options.

For instance, here a list of tuple parameters are created, where it is only a valid combination if parameter 1 is larger than parameter 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 ]
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!