NumPy·Lesson 5·10 min·0/4 exercises

Indexing and slicing

One range per axis — and why an integer removes an axis while a slice keeps it.

a[i, j]start:stop:stepa[:, 1]negative indices...a[i][j]

Watch it happen

Play it through, or step back and forth yourself.

a
0
1
2
0
1
2
3
0
1
2
3
4
5
6
7
8
9
10
11
shape (3, 4)
a[2, 1]
9a plain number — both axes indexed away

a[2, 1] — row 2, column 1, separated by a comma. You'll also see a[2][1], which gets there by pulling out row 2 first and then indexing that. Same answer, more work, and it can't express a[:, 1]. Use the comma.

The idea

Indexing an array takes one index per axis, separated by commas. a[2, 1] is row 2, column 1.

You'll also see a[2][1]. It reaches the same answer by pulling out row 2 as a whole array and then indexing that — an extra temporary, slightly slower, and it can't express "column 1 of every row" at all. Use the comma form.

Ranges

Each position accepts a Python slice, start:stop:step, with stop excluded as usual. A bare : means the whole axis.

a[1, :]        # row 1, every column
a[:, 2]        # column 2 of every row
a[0:2, 1:3]    # rows 0-1 crossed with columns 1-2
a[::2]         # every second row
a[:, ::-1]     # every row reversed
a[-1]          # last row
a[:, -2:]      # last two columns

Negative indices count from the end, exactly as in a Python list. Omitting start means "from the beginning"; omitting stop means "to the end".

Hand-drawn notes showing the anatomy of a slice, with the stop excluded and negative indices counting back from the end.

The rank trap

This is the part worth slowing down for. An integer removes an axis. A slice keeps it.

a[:, 2].shape      # (3,)    — 1-D, the column axis is gone
a[:, 2:3].shape    # (3, 1)  — 2-D, the axis survived as length 1
a[1, :].shape      # (4,)
a[1:2, :].shape    # (1, 4)

Same numbers, different rank. It matters because rank drives broadcasting: a (3,) lines up against the last axis, while a (3, 1) lines up against the first. When you hit "operands could not be broadcast together" in a few lessons' time, an accidental integer index is a prime suspect.

Index every axis with integers and they all disappear — you get a plain number back rather than an array.

Hand-drawn notes showing that indexing a grid with an integer drops the axis and returns a 1-D result, while slicing the same column keeps it 2-D.

Ellipsis

For higher-dimensional arrays, ... stands for "as many full slices as needed":

photo[..., 0]      # first channel, whatever the rank
photo[:, :, 0]     # the same thing, spelled out for a 3-D array

Useful when code should work for both a 2-D and a 3-D input.

One thing this lesson has quietly avoided: none of these expressions copy anything. That's the next lesson, and it's where the real bugs are.

Practice

Write it yourself. The answer is there when you want it.

Putting the kettle on…

Starting up…

Write it yourself

not graded

Print a, then the single element a[2, 1], then the block a[0:2, 1:3]. Now the rank trap: print the shapes of a[:, 2] and a[:, 2:3] one after the other — one drops the axis, one keeps it. Finish with every row reversed.

Write something and press Run — the output appears here.

Your turn

4 exercises. Write the code yourself, then press Check — a nudge and the answer are there if you want them.

Return the value at row 1, column 3 of a.

your answer

Return the last column of cups as a 1-D array.

your answer

Return column 2 of a but keep it 2-D — shape (3, 1), not (3,).

your answer

Return the bottom-right 2×2 corner of a.

your answer