使用 dask 将 iterable.product 转换为 numpy/dask 数组(创建每个排列的矩阵并重复)
Use dask for an out of core conversion of iterable.product into a numpy/dask array (create a matrix of every permutation with repetition)
我想创建一个矩阵(numpy 数组的 numpy 数组),每个排列都有重复(我想稍后将其用于矩阵乘法)。目前我这样做的方式是,我首先创建一个列表列表,然后使用 itertools,然后转换为 numpy 数组的 numpy 数组。然而,作为 R,每个排列的长度增加了 numpy 数组的大小呈指数增长并导致内存错误。所以,我想在 dask 中生成一个矩阵。我浏览了 dask 教程,但还没有弄清楚如何执行此操作。
例如从-1到1(含)的数字每5个数字组合使用步长0.1(r = 5,n = 21):
# 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)
创建长度为 5 的排列已经是我的笔记本电脑可以处理的最大值,因为我使用的是 N = 21。但是当我尝试执行长度为 6 时,我已经遇到内存错误。
我已经尝试创建一个函数并将 dask 延迟与列表理解和 dask.array.from_array() 一起使用,但我对 dask 还是很陌生,还没有找到解决方案。
理想情况下,我可以将排列 (R) 的长度从 5 增加到 10-20 左右(使用相同的 N = 21 或将其一直减少到 N = 5),任何高于此的值拥有它会很棒,但不是必需的。
内存问题是由于这一行:
lst = list(itertools.product(*lst))
如果没有 list()
,这将是一个生成器,因此不需要大量内存。因此,一个解决方案可能是检查下游的矩阵运算,看看它们是否可以在您尝试构建的矩阵的子集上执行(在块或 row/column-wise 切片上)。如果这样 subset-operations 是可能的,那么可以重构代码以使用子集。
如果这不可能,那么使用 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)
的分区数是 a
和 b
的分区数的乘积,因此您将要试验最有意义的拆分为您的用例。
我想创建一个矩阵(numpy 数组的 numpy 数组),每个排列都有重复(我想稍后将其用于矩阵乘法)。目前我这样做的方式是,我首先创建一个列表列表,然后使用 itertools,然后转换为 numpy 数组的 numpy 数组。然而,作为 R,每个排列的长度增加了 numpy 数组的大小呈指数增长并导致内存错误。所以,我想在 dask 中生成一个矩阵。我浏览了 dask 教程,但还没有弄清楚如何执行此操作。
例如从-1到1(含)的数字每5个数字组合使用步长0.1(r = 5,n = 21):
# 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)
创建长度为 5 的排列已经是我的笔记本电脑可以处理的最大值,因为我使用的是 N = 21。但是当我尝试执行长度为 6 时,我已经遇到内存错误。
我已经尝试创建一个函数并将 dask 延迟与列表理解和 dask.array.from_array() 一起使用,但我对 dask 还是很陌生,还没有找到解决方案。
理想情况下,我可以将排列 (R) 的长度从 5 增加到 10-20 左右(使用相同的 N = 21 或将其一直减少到 N = 5),任何高于此的值拥有它会很棒,但不是必需的。
内存问题是由于这一行:
lst = list(itertools.product(*lst))
如果没有 list()
,这将是一个生成器,因此不需要大量内存。因此,一个解决方案可能是检查下游的矩阵运算,看看它们是否可以在您尝试构建的矩阵的子集上执行(在块或 row/column-wise 切片上)。如果这样 subset-operations 是可能的,那么可以重构代码以使用子集。
如果这不可能,那么使用 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)
的分区数是 a
和 b
的分区数的乘积,因此您将要试验最有意义的拆分为您的用例。