使用 range() 或 slice() 对二维 ndarray 进行切片的区别

Differences in using range() or slice() to slice a 2-d ndarray

当我尝试了解 slice() 的工作原理时,我在使用 range() 与 slice() 时遇到了一些有趣的结果。我不知道如何解释这个机制。任何帮助将不胜感激。

例如: 给定一个 np 数组:

a = np.array(range(100)).reshape(10,10)

a[slice(0,10,2)]a[range(0,10,2)] 相同。

然而,

a[(slice(0,10,2),slice(0,10,2))] 

[[0,2...],[20,22...],[40,42,44]...]

但是

a[(range(0,10,2),range(0,10,2))] 

[0,22,44,66...]

谁能解释一下?

一般来说,范围索引和切片索引是两种截然不同的事情。您碰巧遇到了一个给出相同结果的情况,但请注意,切片版本创建了底层缓冲区的 view,而使用 range 对象进行索引会创建一个新的底层缓冲区。

所以注意:

>>> a = np.array(range(100)).reshape(10,10)
>>> s = a[slice(0,10,2)]
>>> r = a[range(0,10,2)]
>>> a[0,0] = 1000
>>> a
array([[1000,    1,    2,    3,    4,    5,    6,    7,    8,    9],
       [  10,   11,   12,   13,   14,   15,   16,   17,   18,   19],
       [  20,   21,   22,   23,   24,   25,   26,   27,   28,   29],
       [  30,   31,   32,   33,   34,   35,   36,   37,   38,   39],
       [  40,   41,   42,   43,   44,   45,   46,   47,   48,   49],
       [  50,   51,   52,   53,   54,   55,   56,   57,   58,   59],
       [  60,   61,   62,   63,   64,   65,   66,   67,   68,   69],
       [  70,   71,   72,   73,   74,   75,   76,   77,   78,   79],
       [  80,   81,   82,   83,   84,   85,   86,   87,   88,   89],
       [  90,   91,   92,   93,   94,   95,   96,   97,   98,   99]])
>>> s
array([[1000,    1,    2,    3,    4,    5,    6,    7,    8,    9],
       [  20,   21,   22,   23,   24,   25,   26,   27,   28,   29],
       [  40,   41,   42,   43,   44,   45,   46,   47,   48,   49],
       [  60,   61,   62,   63,   64,   65,   66,   67,   68,   69],
       [  80,   81,   82,   83,   84,   85,   86,   87,   88,   89]])
>>> r
array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9],
       [20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
       [40, 41, 42, 43, 44, 45, 46, 47, 48, 49],
       [60, 61, 62, 63, 64, 65, 66, 67, 68, 69],
       [80, 81, 82, 83, 84, 85, 86, 87, 88, 89]])

当您使用切片时,您将获得切片语义。范围对象被视为一系列索引。这会触发 advanced indexing behavior

所以从文档中可以看出:

When the index consists of as many integer arrays as the array being indexed has dimensions, the indexing is straight forward, but different from slicing.

所以,ARR[[x1, x2, ..., xn], [y1, y2, ..., yn]] 会给你

[ARR[x1,y1], ARR[x2,y2], ... ARR[xn, yn]]

正如@ShadowRanger 在评论中指出的那样,如果您想要 使用范围索引的复制语义,您仍然应该使用a[:10:2,:10:2].copy(),因为它会更快。