NumPy Cheatsheet

Indexing and Slicing

Use this NumPy reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

Basic Indexing (single elements)

import numpy as np

a = np.array([10, 20, 30, 40, 50])
a[0]     # 10
a[-1]    # 50
a[-2]    # 40

b = np.array([[1, 2, 3],
              [4, 5, 6],
              [7, 8, 9]])
b[0, 0]    # 1   — preferred multi-axis syntax
b[0][0]    # 1   — equivalent but slower (creates intermediate view)
b[-1, -1]  # 9
b[1, 2]    # 6

Basic Slicing

Syntax: start:stop:step along each axis. All parts optional. Returns a view.

a = np.arange(10)    # [0, 1, 2, ..., 9]

a[2:5]      # [2, 3, 4]      stop is exclusive
a[:3]       # [0, 1, 2]
a[7:]       # [7, 8, 9]
a[::2]      # [0, 2, 4, 6, 8]
a[::-1]     # [9, 8, ..., 0]  reversed
a[1:8:2]    # [1, 3, 5, 7]

b = np.arange(12).reshape(3, 4)
b[0, :]     # first row  → [0, 1, 2, 3]
b[:, 1]     # second col → [1, 5, 9]
b[1:, ::2]  # rows 1+, every other col
b[:2, 1:3]  # top-left 2×2 sub-matrix

Ellipsis and newaxis

c = np.ones((2, 3, 4, 5))
c[0, ..., 2]         # ... expands to all middle axes → shape (3, 4)
c[np.newaxis, ...]   # add axis at front → shape (1, 2, 3, 4, 5)
c[:, np.newaxis]     # add axis at position 1

# np.newaxis is just None
a[:, None]           # equivalent to a[:, np.newaxis]

Fancy Indexing (always returns a copy)

Integer array indexing

a = np.array([10, 20, 30, 40, 50])
idx = np.array([0, 2, 4])
a[idx]               # [10, 30, 50]
a[[0, 2, 4]]         # same, inline

b = np.array([[1, 2], [3, 4], [5, 6]])
b[[0, 2], :]         # rows 0 and 2 → [[1,2],[5,6]]
b[[0, 1], [1, 0]]    # elements (0,1) and (1,0) → [2, 3]  — paired indexing

Selecting rows/cols independently

rows = np.array([0, 2])
cols = np.array([1])
b[np.ix_(rows, cols)]   # outer product of indices → shape (2, 1)

Nested fancy indexing

a = np.arange(27).reshape(3, 3, 3)
a[[0, 1], :, [2, 1]]    # shape (2, 3) — axes 0 and 2 zipped

Boolean / Mask Indexing

a = np.array([1, -2, 3, -4, 5])
mask = a > 0
a[mask]          # [1, 3, 5]
a[a > 0]         # same inline
a[a < 0] = 0     # in-place assignment through mask

b = np.arange(12).reshape(3, 4)
b[b % 2 == 0]   # all even values, 1-D result (flattens)

Gotcha: boolean indexing always returns a copy, not a view.

Assignment via Indexing

a = np.zeros(5)
a[2] = 9             # scalar assigned to one element
a[1:4] = [7, 8, 9]  # slice assignment (broadcasts if right side is scalar)
a[[0, 4]] = 99       # fancy-index assignment
a[a < 5] = -1        # mask assignment

# Repeated fancy-index writes: last write wins (no accumulation)
a = np.zeros(5)
a[[1, 1]] = [10, 20]   # a[1] == 20, not 30

# Use np.add.at for accumulation
np.add.at(a, [1, 1], [10, 20])   # a[1] == 30

np.take and np.choose

a = np.array([10, 20, 30, 40])
np.take(a, [0, 3, 1])            # [10, 40, 20]
np.take(b, [0, 2], axis=0)       # rows 0 and 2 of 2-D array

choices = np.array([[0, 1, 2, 3],
                    [10, 11, 12, 13],
                    [20, 21, 22, 23]])
np.choose([0, 1, 2, 0], choices)  # [0, 11, 22, 3]  — pick from each row

Searching for Indices

a = np.array([10, 20, 30, 20, 10])
np.where(a == 20)            # (array([1, 3]),)
np.where(a == 20)[0]         # [1, 3]

np.nonzero(a)                # same as np.where — indices of nonzero elements
np.flatnonzero(a > 15)       # flat indices

np.argmax(a)                 # index of max → 2
np.argmin(a)                 # index of min → 0
np.argmax(b, axis=0)         # per-column max index
np.argsort(a)                # indices that would sort a
np.argpartition(a, 2)        # partial-sort indices (nth smallest at index 2)

np.searchsorted([1, 3, 5], 4)         # insertion index → 2
np.searchsorted([1, 3, 5], [2, 4])   # [1, 2]
np.searchsorted([1, 3, 5], 3, side="right")  # → 2

Advanced: np.unravel_index / np.ravel_multi_index

a = np.arange(24).reshape(4, 6)
flat_idx = np.argmax(a)               # 23 (flat index)
np.unravel_index(flat_idx, a.shape)   # (3, 5)  — row, col

np.ravel_multi_index((3, 5), (4, 6))  # 23 — reverse: multi → flat
np.ravel_multi_index(([1, 2], [3, 4]), (4, 6))  # [9, 16]

Slicing Summary Table

ExpressionReturnsView?
a[i]single element or sub-arrayyes
a[i:j]sliceyes
a[i:j:k]stepped sliceyes
a[...]ellipsis sliceyes
a[[i, j]]fancy int indexno
a[bool_mask]boolean maskno
a.take(idx)like fancy but with modesno