Eric Eric - 18 days ago 9
Python Question

Advanced slicing when passed list instead of tuple in numpy

In the docs, it says (emphasis mine):


Advanced indexing is triggered when the selection object, obj, is a
non-tuple sequence object
, an ndarray (of data type integer or bool),
or a tuple with at least one sequence object or ndarray (of data type
integer or bool). There are two types of advanced indexing: integer
and Boolean.

<snip>

Also recognize that
x[[1,2,3]]
will trigger advanced indexing, whereas
x[[1,2,slice(None)]]
will trigger basic slicing
.


I know why
x[(1, 2, slice(None))]
triggers basic slicing. But why does
x[[1,2,slice(None)]]
trigger basic slicing, when
[1,2,slice(None)]
meets the condition of being a non-tuple sequence?




On a related note, why does the following occur?

>>> a = np.eye(4)
>>> a[(1, 2)] # basic indexing, as expected
0.0
>>> a[(1, np.array(2))] # basic indexing, as expected
0.0

>>> a[[1, 2]] # advanced indexing, as expected
array([[ 0., 1., 0., 0.],
[ 0., 0., 1., 0.]])
>>> a[[1, np.array(2)]] # basic indexing!!??
0.0

Answer

There's an exception to that rule. The Advanced Indexing documentation section doesn't mention it, but up above, near the start of the Basic Slicing and Indexing section, you'll see the following text:

In order to remain backward compatible with a common usage in Numeric, basic slicing is also initiated if the selection object is any non-ndarray sequence (such as a list) containing slice objects, the Ellipsis object, or the newaxis object, but not for integer arrays or other embedded sequences.


a[[1, np.array(2)]] doesn't quite trigger basic indexing. It triggers an undocumented part of the backward compatibility logic, as described in a comment in the source code:

    /*
     * Sequences < NPY_MAXDIMS with any slice objects
     * or newaxis, Ellipsis or other arrays or sequences
     * embedded, are considered equivalent to an indexing
     * tuple. (`a[[[1,2], [3,4]]] == a[[1,2], [3,4]]`)
     */

The np.array(2) inside the list causes the list to be treated as if it were a tuple, but the result, a[(1, np.array(2))], is still an advanced indexing operation. It ends up applying the 1 and the 2 to separate axes, unlike a[[1, 2]], and the result ends up looking identical to a[1, 2], but if you try it with a 3D a, it produces a copy instead of a view.

Comments