Evgeny P. Kurbatov
Evgeny P. Kurbatov

Reputation: 193

Indexing numpy multidimensional arrays depends on a slicing method

I have a 3-D array. When I take a 2-D slice of it the result depends on whether it is indexed with a list or with a slice. In the first case the result is transposed. Didn't find this behaviour in the manual.

>>> import numpy as np
>>> x = np.array([[[1,1,1],[2,2,2]], [[3,3,3],[4,4,4]]])
>>> x
array([[[1, 1, 1],
        [2, 2, 2]],
       [[3, 3, 3],
        [4, 4, 4]]])
>>> x[0,:,[0,1]]
array([[1, 2],
       [1, 2]])
>>> x[0,:,slice(2)]
array([[1, 1],
       [2, 2]])
>>> 

Could anyone point a rationale for this?

Upvotes: 3

Views: 868

Answers (2)

juanpa.arrivillaga
juanpa.arrivillaga

Reputation: 96285

Because you are actually using advanced indexing when you use [0,1]. From the docs:

Combining advanced and basic indexing

When there is at least one slice (:), ellipsis (...) or np.newaxis in the index (or the array has more dimensions than there are advanced indexes), then the behaviour can be more complicated. It is like concatenating the indexing result for each advanced index element

In the simplest case, there is only a single advanced index. A single advanced index can for example replace a slice and the result array will be the same, however, it is a copy and may have a different memory layout. A slice is preferable when it is possible.

Pay attention to the two parts I've bolded above.

In particular, in this construction:

>>> x[0,:,[0,1]]
array([[1, 2],
       [1, 2]])

Is the case where there is at least once "slice, ellipsisi, or np.newaxis" in the index, and the behavior is like concatenating the indexing result for each advanced index element. So:

>>> x[0,:,[0]]
array([[1, 2]])
>>> x[0,:,[1]]
array([[1, 2]])
>>> np.concatenate((x[0,:,[0]], x[0,:,[1]]))
array([[1, 2],
       [1, 2]])

However, this construction is like the simple case: there is only a single advanced index, so it acts like a slice:

>>> x[0,:,slice(2)]
array([[1, 1],
       [2, 2]])
>>> x[slice(0,1),:,slice(2)]
array([[[1, 1],
        [2, 2]]])

Although note, that the later is actually three dimensional because the first part of the index acted as a slice, it's 3 slices so three dimensions.

Upvotes: 5

kmario23
kmario23

Reputation: 61485

As I understand it, NumPy is following the axis numbering philosophy when it spits out the result when given a list/tuple-like index.

array([[[1, 1, 1],
        [2, 2, 2]],

       [[3, 3, 3],
        [4, 4, 4]]])

When you already specify the first two indices (x[0, :, ]), now the next question is how to extract the third dimension. Now, when you specify a tuple (0,1), it first extracts the 0th slice axis wise, so it gets [1, 2] since it lies in 0th axis, next it extracts 1st slice likewise and stacks below the already existing row [1, 2].

[[1, 1, 1],          array([[1, 2],
 [2, 2, 2]]  =====>         [1, 2]])

(visualize this stacking as below (not on top of) the already existing row since axis-0 grows downwards)enter image description here

Alternatively, it is following the slicing philosophy (start:stop:step) when slice(n) is given for the index. Note that using slice(2) is essentially equal to 0:2 in your example. So, it extracts [1, 1] first, then [2, 2]. Note, here to how [1, 1] comes on top of [2, 2], again following the same axis philosophy here since we didn't leave the third dimension yet. This is why this result is the transpose of the other.

array([[1, 1],
       [2, 2]])

Also, note that starting from 3-D arrays this consistency is preserved. Below is an example from 4-D array and the slicing results.

In [327]: xa
Out[327]: 
array([[[[ 0,  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]]]])

In [328]: xa[0, 0, :, [0, 1]]
Out[328]: 
array([[0, 3, 6],
       [1, 4, 7]])

In [329]: xa[0, 0, :, 0:2]
Out[329]: 
array([[0, 1],
       [3, 4],
       [6, 7]])

Upvotes: 2

Related Questions