如何减少Python的itertools.product的内存消耗和处理时间?

时间:2018-08-07 14:15:30

标签: python-3.x numpy matrix simulation itertools

我所拥有的

我创建了一个函数,用于为给定数量的行和列以及给定的可能值列表生成所有可能的矩阵。

def generate_matrices(rows, columns, values):
    """Returns an iterable over all possible matrices for a given
       number of rows and columns and a given list of possible
       values.

       Arguments:
           rows    -- number of rows desired for each matrix
           columns -- number of columns desired for each matrix
           values  -- list of values desired for iteration

       Returns:
           returns an iterator over the generated matrices

       Dependencies:
           requires the itertools library (`import itertools`)
    """

    x = itertools.product(values, repeat = columns)
    y = itertools.product(x, repeat = rows)

    return y

我需要什么

这对于较小的输入(行和列的数量少,值很少)有效,但对于较大的输入,在处理函数时会消耗所有系统内存。

如何最小化此功能的内存消耗和处理时间?

这些矩阵的目的是为一组函数提供测试值,以最大化特定公式的输出。如果有更好的方法来测试所有可能的输入是否有可变数量的变量和变量范围,请提出建议。

2 个答案:

答案 0 :(得分:0)

您可以编写一个“惰性”矩阵生成器,例如:

import numpy as np
from itertools import product

def generate_matrices(rows, columns, values, dtype=None):
    dtype = dtype or float
    for mat in generate_matrices_rec(rows, columns, values, np.empty((rows, columns), dtype)):
        yield mat.copy()

def generate_matrices_rec(rows, columns, values, mat):
    if rows <= 0:
        yield mat
    else:
        for row in product(values, repeat=columns):
            mat[0] = row
            for submat in generate_matrices_rec(rows - 1, columns, values, mat[1:]):
                yield mat

然后您可以遍历如下矩阵:

for matrix in generate_matrices(rows, columns, values):
    # Do something with the matrix...

这不应该占用您的内存(当然,除非您尝试将所有生成的矩阵存储在列表或类似的列表中)。但是,可能的矩阵数量在天文数字上会非常快地增长(特别是len(values) ** (rows * columns)),因此即使您没有用完内存,也会很容易用完时间。

答案 1 :(得分:0)

仅通过阅读代码就很难想象发生了什么。因此,这是一个小例子(如果您确实需要帮助,您应该为我们做的事情!):

In [201]: x=itertools.product([1,2],repeat=2)
In [202]: list(x)
Out[202]: [(1, 1), (1, 2), (2, 1), (2, 2)]
In [203]: y=itertools.product(Out[202],repeat=2)
In [204]: list(y)
Out[204]: 
[((1, 1), (1, 1)),
 ((1, 1), (1, 2)),
 ((1, 1), (2, 1)),
 ((1, 1), (2, 2)),
 ((1, 2), (1, 1)),
 ((1, 2), (1, 2)),
 ((1, 2), (2, 1)),
 ((1, 2), (2, 2)),
 ((2, 1), (1, 1)),
 ((2, 1), (1, 2)),
 ((2, 1), (2, 1)),
 ((2, 1), (2, 2)),
 ((2, 2), (1, 1)),
 ((2, 2), (1, 2)),
 ((2, 2), (2, 1)),
 ((2, 2), (2, 2))]

因此,即使您反复使用y,它仍然必须创建x可能性的完整列表。

如果我没看错你的问题,你想依次测试由y元素组成的数组,例如:

In [205]: np.array(Out[204][5])
Out[205]: 
array([[1, 2],
       [1, 2]])

例如:

In [206]: x=itertools.product([1,2,3,4],repeat=4)
In [207]: y=itertools.product(x,repeat=3)

In [209]: next(y) 
Out[209]: ((1, 1, 1, 1), (1, 1, 1, 1), (1, 1, 1, 1)) 
In [210]: np.array(_) 
Out[210]: array([[1, 1, 1, 1], 
                 [1, 1, 1, 1], 
                 [1, 1, 1, 1]])

随后的next(y)将产生更多(3,4)数组,并用[1,2,3,4]中的值逐渐替换1。

如何用一种乘积生成所有矩阵值:

In [214]: z = itertools.product([1,2,3,4],repeat=12)
In [215]: np.array(next(z)).reshape(3,4)
Out[215]: 
array([[1, 1, 1, 1],
       [1, 1, 1, 1],
       [1, 1, 1, 1]])

据我所知,它生成的数组与嵌套生成器的数组相同。