稀疏数组
内容
稀疏数组¶
通过将内存中的 NumPy 数组替换为内存中的稀疏数组,我们可以重用 Dask 数组的块算法来实现并行和分布式的稀疏数组。
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 约定。未实现这些操作是可以的;如果在尝试这些操作时,并行的 dask.array
将在运行时出错。
混合数组¶
Dask 的数组支持混合不同类型的内存数组。这依赖于内存数组在必要时知道如何相互交互。当两个数组交互时,具有最高 __array_priority__
的数组的函数将优先执行(例如,对于连接、张量点积等)。