内容

切片

内容

切片

Dask 数组支持大部分 NumPy 切片语法。特别是,它支持以下内容:

  • 按整数和切片进行切片:x[0, :5]

  • 通过整数列表/数组切片:x[[1, 2, 4]]

  • 通过布尔列表/数组的切片:x[[False, True, True, False, True]]

  • 使用布尔类型的 Array 对一个 Array 进行切片:x[x > 0]

  • 使用一个零维或一维的 ArrayArray 进行切片:a[b.argtopk(5)]

然而,它目前不支持以下内容:

  • 在多个轴上使用列表进行切片:x[[1, 2, 3], [3, 2, 1]]

    这很容易添加。如果你有一个用例,那么可以提出一个问题。此外,对此感兴趣的用户应该查看 vindex

  • 使用多维的 Array 对一个 Array 进行切片

效率

普通的 Dask 调度器足够智能,只会计算那些为了达到所需切片而必需的块。因此,如果只需要少量输出,大型操作可能会很廉价。

在下面的示例中,我们创建了一个包含一万亿个元素的Dask数组,每个块的大小为百万个元素。然后我们对整个数组进行操作,最后只切分出输出的一部分:

>>> # Trillion element array of ones, in 1000 by 1000 blocks
>>> x = da.ones((1000000, 1000000), chunks=(1000, 1000))

>>> da.exp(x)[:1500, :1500]
...

这只需要计算左上角的四个块来达到结果。我们在那些只需要部分结果的块上稍微浪费了一些。此外,我们也有点浪费,因为我们仍然需要操作包含大约一百万个任务的Dask图。这可能会导致一两秒的交互开销。

使用具体索引器(例如整数列表)进行切片有几种可能的失败模式值得提及。首先,当你对分块轴进行索引时,Dask通常会在输出上“匹配”分块。

# Array of ones, chunked along axis 0
>>> a = da.ones((4, 10000, 10000), chunks=(1, -1, -1))

如果我们用一个 排序 的整数序列来切片,Dask 将返回每个输入块一个块(注意输出 chunksize 是 1,因为索引 01 在输入中位于不同的块中)。

>>> a[[0, 1], :, :]          
dask.array<getitem, shape=(2, 10000, 10000), dtype=float64, chunksize=(1, 10000, 10000), chunktype=numpy.ndarray>

但是重复的索引呢?Dask 继续为每个输入块返回一个块,但如果您有许多来自同一输入块的重复项,您的输出块可能会大得多。

>>> a[[0] * 15, :, :]
PerformanceWarning: Slicing is producing a large chunk. To accept the large
chunk and silence this warning, set the option
    >>> with dask.config.set({'array.slicing.split_large_chunks': False}):
    ...     array[indexer]

To avoid creating the large chunks, set the option
    >>> with dask.config.set({'array.slicing.split_large_chunks': True}):
    ...     array[indexer]
dask.array<getitem, shape=(15, 10000, 10000), dtype=float64, chunksize=(15, 10000, 10000), chunktype=numpy.ndarray>

之前我们在第一个维度上的chunksize为``1``,因为我们从每个输入块中只选择了一个元素。但现在我们从第一个块中选择了15个元素,生成了一个较大的输出块。

当以这种方式索引产生一个比 array.chunk-size 配置选项大5倍的块时,Dask 会发出警告。你有两个选项来处理这个警告:

  1. 设置 dask.config.set({"array.slicing.split_large_chunks": False}) 以允许大块并静默警告。

  2. 设置 dask.config.set({"array.slicing.split_large_chunks": True}) 以避免首先创建大块。

正确的选择将取决于你的下游操作。有关选择块大小的更多信息,请参见