Lesson 5 of 7

Indexing, masking and fancy selection

Selecting part of an array is four different operations wearing the same square brackets. They differ in what comes back, in what shape it comes back, and in whether writing to it reaches your data.

You already know that basic slicing hands back a window and that fancy indexing and boolean masks hand back new memory. This lesson is the other half of it: what actually comes out of the brackets, and what shape it is in.

Seven ideas, and two rules that carry most of the weight. An integer removes an axis and a slice keeps it. An index array puts its own shape into the result -- and two index arrays in one subscript pair up rather than outlining a rectangle, which is the single most expensive misreading in this lesson.

Every board indexes an array and asks one of four things: which elements come back, what shape they come back in, what the array looks like afterwards, and whether what you are holding is a window onto it. Nothing runs — each answer follows from how the index is written, and so does every wrong option, which is always what some real misreading of the same line would have given you.

1 of 7

One index per axis, separated by commas

An integer removes an axis and a slice keeps it. That single rule is where the rank of everything you select comes from.

An index carries one entry per axis, in order, separated by commas. Axes you do not mention are taken whole:

a.shape == (4, 4)

a[1, 2]      row 1, column 2          one number
a[1]         row 1, every column      the same as a[1, :]
a[1:3, 2]    rows 1 and 2, column 2
a[:, 1:3]    every row, columns 1 and 2

What decides the rank of the result is short enough to say in one line, and it is worth saying in exactly these words:

An integer removes that axis. A slice keeps it.

So on a (4, 4) array, a[1, 2] removes both axes and leaves a scalar, a[1:3, 2] removes one and keeps one, and a[1:3, 2:3] keeps both. Three expressions, overlapping numbers, three different ranks.

The pair that catches everybody is the smallest one:

a[0]      -> shape (4,)     an integer, so axis 0 is gone
a[0:1]    -> shape (1, 4)   a slice, so axis 0 stays, at length one

Same four numbers, different object. a[0:1] is still a stack of rows that happens to hold one row, and it broadcasts, prints and combines like one.

Slices take a step as well, and negative positions count from the end: a[::2] is every other row, a[:, -1] is the last column, and a[::-1] is the rows in reverse.

A slice that runs off the end is clipped rather than raised -- a[2:99] on four rows gives you two. An integer off the end is an IndexError. A slice describes a range, and an empty part of a range is still a range; an integer names an element, and NumPy will not invent one.

Challenge

Slice the Axes

1 of 4

Say which elements come back, and at what rank.

One entry per axis, separated by commas. An integer removes that axis and a slice keeps it, so two of the options below hold the same numbers at different ranks. Read the brackets, not the numbers.