目录

切片

目录

切片

Dask Array 支持大部分 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>

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

正确的选择取决于您的下游操作。有关如何选择块大小的更多信息,请参阅