【问题标题】:How to reduce memory consumption and processing time of Python's itertools.product?如何减少 Python 的 itertools.product 的内存消耗和处理时间?
【发布时间】:2018-08-07 14:15:30
【问题描述】:

我有什么

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

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

我需要什么

这适用于小输入(少量行和列,少量值),但对于较大的输入,所有系统内存都用于处理函数。

我怎样才能最小化这个函数的内存消耗和处理时间?

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

【问题讨论】:

  • 您真的需要测试地球上所有可能的矩阵吗?你为什么不使用hypothesis testing 让框架发挥它的魔力(比如自动缩小哪些矩阵和哪些值会破坏测试)?
  • 什么太大了,所有y 的列表或只是一个迭代。我不知道将 x 放入 y 会做什么。
  • itertools.product 创建一个迭代器,而不是一个列表。如果你一个一个地迭代所有元素,它不应该消耗很多内存。您是否将迭代器转换为列表或做了类似的事情?
  • @Dabiuteef 问题是第二个itertools.product需要运行第一个的结果才能开始生产元素。
  • @NilsWerner 你说的很对——我从错误的角度来处理这个问题。我不会测试所有存在的矩阵,而是只测试那些在给定函数约束的情况下可能出现的矩阵。

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


【解决方案1】:

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

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)),因此即使您没有耗尽内存,也很容易耗尽时间。

【讨论】:

  • 顺便说一句,我为 NumPy 矩阵编写了生成器,因为我假设这是您正在使用的(来自标签),但是编写一个生成列表列表的类似函数同样可行。
  • NumPy 矩阵是完美的。感谢您的解决方案 - 它运行良好并解决了内存问题,但是,正如您所指出的,时间问题在这里并不是真正可以克服的。
【解决方案2】:

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

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 替换为 [1,2,3,4] 中的值。

如何用一个产品生成所有矩阵值:

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]])

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

【讨论】:

  • 感谢您的回答。下次发布问题时,我一定会提供示例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 2019-03-02
  • 2016-05-24
相关资源
最近更新 更多