python - 使用 dask 将 iterable.product 的核心转换为 numpy/dask 数组(创建每个重复排列的矩阵)

我希望为每个重复排列创建一个矩阵(numpy 数组 numpy arrays)(我想稍后将它用于矩阵乘法)。目前我这样做的方式是,我首先创建一个列表列表,然后使用 itertools,然后转换为 numpy arrays 的 numpy 数组。然而,作为 R,每个排列的长度会增加 numpy 数组的大小,并以指数方式增加并导致内存错误。所以,我想在 dask 中生成一个矩阵。我浏览了 dask 教程,但还没有弄清楚如何做到这一点。

例如,使用 0.1 步长(r = 5,n = 21)从 -1 到 1(含)的数字的每 5 个数字组合:

# Create 5 lists each with 21 elements
lst = []
for i in range(0,5):
    lst.append(np.linspace(-1,1,21).tolist())
lst

# Convert to a list of tuples, each tuple is a permutation e.g. -1,-1,-1,-1,-1 or -1,-1,-1,-1,-0.9
lst = list(itertools.product(*lst))
# Convert to a numpy array of numpy arrays for matrix multiplication later on
mat = np.array(lst)

鉴于我使用 N = 21,创建长度为 5 的排列已经是我的笔记本电脑可以处理的最大值。但是在尝试长度为 6 时我已经遇到了内存错误。

我已经尝试创建一个函数并将 dask 延迟与列表理解以及 dask.array.from_array() 一起使用,但我对 dask 仍然很陌生,还没有找到解决方案。

理想情况下,我可以将排列 (R) 的长度从 5 增加到 10-20 左右(使用相同的 N = 21 或将其一直减小到 N = 5),任何高于此的都很棒但不是必需的。

回答1

内存问题是由于这一行:

lst = list(itertools.product(*lst))

如果没有 list() 这将是一个生成器,因此不需要大量内存。因此,一个解决方案可能是检查下游的矩阵运算,看看它们是否可以在您尝试构建的矩阵的子集上执行(在块或行/列切片上)。如果这样的子集操作是可能的,那么可以重构代码以使用子集。

如果这是不可能的,那么使用 dask.bags 的以下方法可能会有所帮助:

from dask import compute
from dask.bag import from_sequence

a = from_sequence([1, 2], npartitions=2)
b = from_sequence([3, 6, 9], npartitions=2)

print(*compute(a.product(b)))
# [(1, 3), (1, 6), (2, 3), (2, 6), (1, 9), (2, 9)]

或更接近您的示例:

from dask.bag import from_sequence
from numpy import linspace

a = from_sequence(linspace(1, 10, 10), npartitions=2)
b = from_sequence(linspace(20, 30, 10), npartitions=2)
c = a.product(b)
print(c.to_dataframe().to_dask_array(lengths=True))
# dask.array<values, shape=(100, 2), dtype=float64, chunksize=(25, 2), chunktype=numpy.ndarray>

请注意,a.product(b) 的分区数是 ab 的分区数的乘积,因此您需要尝试对您的用例最有意义的拆分。

相似文章

最新文章