Indexing and slicing

NumPy · Essentials · 12 min

Selecting parts of arrays is in almost every line of numerical code, and slices are free because they are views.

Indexing a 1-D array works like a list: a[0], a[-1], a[2:5], a[::2]. Multi-dimensional arrays take one index per axis, separated by commas: m[1, 2] is row 1, column 2. Prefer this over m[1][2], which first builds a row and then indexes it.

Each position can be an integer or a slice:

  • m[0] or m[0, :]: the first row (shape drops by one dimension)
  • m[:, 1]: the second column, as a 1-D array
  • m[1:, :2]: rows from 1 on, first two columns, still 2-D
  • m[..., 0]: the ellipsis stands for "all remaining axes", useful for arrays like images of shape (h, w, 3)

An integer index removes that axis; a slice keeps it, even if it's length 1. So m[:, 1] has shape (rows,) while m[:, 1:2] has shape (rows, 1).

The big difference from lists: a slice of an ndarray is a view, not a copy. Modifying sub = m[:2, :2] modifies m. This lets you work on a window of a big array without copying, but can surprise you if you expected independence. Use .copy() when you need a separate array.

You can also assign through indexes: m[0] = 0 sets a whole row, and m[:, 1] = [7, 8, 9] writes a column. The right side must match or broadcast to the selected shape.

Example

import numpy as np

m = np.arange(12).reshape(3, 4)
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]]
print(m[1, 2])          # 6
print(m[:, 1])          # [1 5 9]      shape (3,)
print(m[:, 1:2].shape)  # (3, 1)
print(m[1:, :2])        # [[4 5] [8 9]]
print(m[::2, ::-1])     # rows 0 and 2, columns reversed

sub = m[:2, :2]         # a view
sub[:] = 0
print(m[0])             # [0 0 2 3]  -- original changed

safe = m[:, 0].copy()
m[:, 0] = [7, 8, 9]     # assign a column
print(safe, m[:, 0])    # [0 0 8] [7 8 9]

Remember

  • Use one comma-separated index per axis: m[r, c]
  • Integers drop an axis, slices keep it
  • Slices are views: writing to them changes the original
  • Call .copy() when you need an independent piece

Watch out for

  • Expecting b = a[2:5] to be a copy as with lists, then being surprised when changing b changes a.

Check yourself

  1. `m` has shape (4, 5). What is the shape of `m[2, 1:4]`?
  2. After `a = np.arange(5); b = a[1:3]; b[0] = 50`, what is `a`?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: numpy.org/doc/stable/user/basics.indexing.html