9

If I slice a 2d array with a set of coordinates

>>> test = np.reshape(np.arange(40),(5,8))
>>> coords = np.array((1,3,4))
>>> slice = test[:, coords]

then my slice has the shape that I would expect

>>> slice.shape
(5, 3)

But if I repeat this with a 3d array

>>> test = np.reshape(np.arange(80),(2,5,8))
>>> slice = test[0, :, coords]

then the shape is now

>>> slice.shape
(3, 5)

Is there a reason that these are different? Separating the indices returns the shape that I would expect

>>> slice = test[0][:][coords]
>>> slice.shape
(5, 3)

Why would these views have different shapes?

1

2 Answers 2

6
slice = test[0, :, coords]

is simple indexing, in effect saying "take the 0th element of the first coordinate, all of the second coordinate, and [1,3,4] of the third coordinate". Or more precisely, take coordinates (0,whatever,1) and make it our first row, (0,whatever,2) and make it our second row, and (0,whatever,3) and make it our third row. There are 5 whatevers, so you end up with (3,5).

The second example you gave is like this:

slice = test[0][:][coords]

In this case you're looking at a (5,8) array, and then taking the 1st, 3rd and 4th elements, which are the 1st, 3rd and 4th rows, so you end up with a (5,3) array.

Edit to discuss 2D case:

In the 2D case, where:

>>> test = np.reshape(np.arange(40),(5,8))
>>> test
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, 36, 37, 38, 39]])

the behaviour is similar.

Case 1:

>>> test[:,[1,3,4]]
array([[ 1,  3,  4],
       [ 9, 11, 12],
       [17, 19, 20],
       [25, 27, 28],
       [33, 35, 36]])

is simply selecting columns 1,3, and 4.

Case 2:

>>> test[:][[1,3,4]]
array([[ 8,  9, 10, 11, 12, 13, 14, 15],
       [24, 25, 26, 27, 28, 29, 30, 31],
       [32, 33, 34, 35, 36, 37, 38, 39]])

is taking the 1st, 3rd and 4th element of the array, which are the rows.

Sign up to request clarification or add additional context in comments.

3 Comments

This makes sense for the 3d case, but why is the 2d case different? Why isn't it taking (whatever,1) as the first row?
So when you put the 0 into the 3D case, it means you have a mixture of simple and advanced indexing. The advanced index always become the first index, which is what swaps it around.
In the 2D case, there's no mixture, so it maintains the existing order.
4

http://docs.scipy.org/doc/numpy/reference/arrays.indexing.html#combining-advanced-and-basic-indexing

The docs talk about the complexity of combining advanced and basic indexing.

test[0, :, coords]

The indexing coords comes first, with the [0,:] after, producing the the (3,5).

The easiest way to understand the situation may be to think in terms of the result shape. There are two parts to the indexing operation, the subspace defined by the basic indexing (excluding integers) and the subspace from the advanced indexing part. [in the case where]

The advanced indexes are separated by a slice, ellipsis or newaxis. For example x[arr1, :, arr2]. .... the dimensions resulting from the advanced indexing operation come first in the result array, and the subspace dimensions after that.

I recall discussing this kind of indexing in a previous SO question, but it would take some digging to find it.

https://stackoverflow.com/a/28353446/901925 Why does the order of dimensions change with boolean indexing?

How does numpy order array slice indices?


The [:] in test[0][:][coords] does nothing. test[0][:,coords] produces the desired (5,3) result.

In [145]: test[0,:,[1,2,3]]   # (3,5) array
Out[145]: 
array([[ 1,  9, 17, 25, 33],   # test[0,:,1]
       [ 2, 10, 18, 26, 34],
       [ 3, 11, 19, 27, 35]])

In [146]: test[0][:,[1,2,3]]   # same values but (5,3)
Out[146]: 
array([[ 1,  2,  3],
       [ 9, 10, 11],
       [17, 18, 19],
       [25, 26, 27],
       [33, 34, 35]])

In [147]: test[0][:][[1,2,3]]   # [:] does nothing; select 3 from 2nd axis
Out[147]: 
array([[ 8,  9, 10, 11, 12, 13, 14, 15],
       [16, 17, 18, 19, 20, 21, 22, 23],
       [24, 25, 26, 27, 28, 29, 30, 31]])

In [148]: test[0][[1,2,3]]   # same as test[0,[1,2,3],:]
Out[148]: 
array([[ 8,  9, 10, 11, 12, 13, 14, 15],
       [16, 17, 18, 19, 20, 21, 22, 23],
       [24, 25, 26, 27, 28, 29, 30, 31]])

1 Comment

This answer makes a lot of sense, except it still doesn't explain why the 2D case behaves the way it does!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.