目录

切片

目录

切片

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

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

  • 按整数列表/数组进行切片:x[[1, 2, 4]]

  • 按布尔值列表/数组进行切片:x[[False, True, True, False, True]]

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

  • 使用零维或一维整数 Array 对一个 Array 进行切片:a[b.argtopk(5)]

但是,它目前不支持以下方式:

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

    虽然添加此功能很简单。如果您有使用场景,请提出 issue。此外,对此感兴趣的用户应该查看 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>

之前我们在第一个维度上的块大小是 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}) 以避免创建大块。

正确的选择取决于您的后续操作。有关选择块大小的更多信息,请参阅 分块