Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Slicing 3d numpy array returns strange shape

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?

like image 893
Ryan Loomis Avatar asked Jul 14 '15 18:07

Ryan Loomis


2 Answers

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.

like image 80
Dr Xorile Avatar answered Oct 21 '22 18:10

Dr Xorile


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]])
like image 40
hpaulj Avatar answered Oct 21 '22 18:10

hpaulj