NumPy Cheatsheet
Indexing and Slicing
Use this NumPy reference while you build software engineering projects, review code, or refresh the syntax you reach for most.
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
| Expression | Returns | View? |
|---|---|---|
a[i] | single element or sub-array | yes |
a[i:j] | slice | yes |
a[i:j:k] | stepped slice | yes |
a[...] | ellipsis slice | yes |
a[[i, j]] | fancy int index | no |
a[bool_mask] | boolean mask | no |
a.take(idx) | like fancy but with modes | no |