稀疏数组
目录
稀疏数组¶
通过将内存中的 NumPy 数组替换为内存中的稀疏数组,我们可以重用 Dask Array 的分块算法来实现并行和分布式的稀疏数组。
Dask Array 中的分块算法通常围绕内存中的 NumPy 数组进行并行化。然而,如果另一个内存数组库支持 NumPy 接口,那么它也可以利用 Dask Array 的并行算法。特别是 sparse 数组库满足了 NumPy API 的一个子集,并且与 Dask Array 配合良好(并经过测试)。
示例¶
假设我们有一个主要由零组成的 Dask 数组
rng = da.random.default_rng()
x = rng.random((100000, 100000), chunks=(1000, 1000))
x[x < 0.95] = 0
我们可以将每个 NumPy 数组块转换为一个 sparse.COO 数组
import sparse
s = x.map_blocks(sparse.COO)
现在,我们的数组不再由许多 NumPy 数组组成,而是由许多稀疏数组组成。从语义上讲,这没有任何改变。可以工作的操作将继续以相同的方式工作(假设 numpy
和 sparse
的行为相同),但性能特征和存储成本可能会发生显著变化
>>> s.sum(axis=0)[:100].compute()
<COO: shape=(100,), dtype=float64, nnz=100>
>>> _.todense()
array([ 4803.06859272, 4913.94964525, 4877.13266438, 4860.7470773 ,
4938.94446802, 4849.51326473, 4858.83977856, 4847.81468485,
... ])
要求¶
任何复制 NumPy ndarray 接口的内存库都应该在这里工作。sparse 库就是一个最简示例。特别是,内存库至少应实现以下操作
使用切片、列表和元素进行简单切片(用于切片、重新分块、重塑等)
与
np.concatenate
接口匹配的concatenate
函数。此函数必须注册在dask.array.core.concatenate_lookup
中所有 ufuncs 都必须支持完整的 ufunc 接口,包括
dtype=
和out=
参数(即使它们不能正常工作)所有归约操作都必须支持完整的
axis=
和keepdims=
关键字,并在这方面表现得像 NumPy数组类应遵循
__array_priority__
协议,并准备好响应优先级较低的其他数组如果需要
dot
支持,应在dask.array.core.tensordot_lookup
中注册一个与np.tensordot
接口匹配的tensordot
函数
reshape、transpose 等其他操作的实现应遵循 NumPy 关于形状和 dtype 的标准惯例。不实现这些操作是可以的;如果尝试进行这些操作,并行 dask.array
将在运行时报错。
混合数组¶
Dask 的 Array 支持混合使用不同类型的内存数组。这依赖于内存数组在必要时知道如何相互交互。当两个数组交互时,具有最高 __array_priority__
的数组中的函数将优先(例如,对于 concatenate, tensordot 等)。