Lookups, reordering by argsort, sampling rows and one-hot style encodings all rely on integer array indexing.
When the index is an array (or list) of integers, NumPy performs advanced indexing, often called fancy indexing: it gathers the elements at those positions. a[[3, 0, 3]] returns a new array with elements 3, 0 and 3, in that order, repeats allowed.
The result's shape is the shape of the index array, not of a. So a[np.array([[0, 1], [2, 3]])] returns a 2x2 array. This makes fancy indexing a vectorized lookup table: palette[image] turns an array of colour ids of shape (h, w) into RGB pixels of shape (h, w, 3).
With several index arrays, they are paired up element by element: m[[0, 1, 2], [2, 0, 1]] returns m[0, 2], m[1, 0], m[2, 1]. That is not the same as selecting a sub-block. For "rows 0 and 2, columns 1 and 3" use m[np.ix_([0, 2], [1, 3])], or index in two steps m[[0, 2]][:, [1, 3]].
Mixing a slice with an index array works per axis: m[:, [2, 0]] reorders columns.
Two important behaviours:
- Fancy indexing always returns a copy, unlike slicing.
- When assigning with repeated indices, each repeat simply overwrites:
a[[0, 0]] += 1incrementsa[0]only once. To accumulate repeats, use the unbuffered ufunc methodnp.add.at(a, idx, 1), ornp.bincountfor counts.
A typical pairing is order = np.argsort(keys) followed by values[order], which sorts one array by another.
Example
import numpy as np
a = np.array([10, 20, 30, 40, 50])
print(a[[3, 0, 3]]) # [40 10 40]
print(a[np.array([[0, 1], [4, 4]])]) # [[10 20] [50 50]]
m = np.arange(12).reshape(3, 4)
print(m[[0, 1, 2], [2, 0, 1]]) # [2 4 9] paired positions
print(m[np.ix_([0, 2], [1, 3])]) # [[ 1 3] [ 9 11]] a sub-block
print(m[:, [3, 0]]) # columns reordered
palette = np.array([[0, 0, 0], [255, 0, 0], [0, 255, 0]])
img = np.array([[0, 1], [2, 1]])
print(palette[img].shape) # (2, 2, 3)
counts = np.zeros(3, dtype=int)
idx = np.array([0, 2, 2, 2])
counts[idx] += 1
print(counts) # [1 0 1] repeats not accumulated
counts[:] = 0
np.add.at(counts, idx, 1)
print(counts) # [1 0 3]Remember
- An integer array index gathers elements; result shape = index shape
- Multiple index arrays pair up element-wise; use
np.ix_for sub-blocks - Fancy indexing returns a copy
- Use
np.add.atornp.bincountwhen indices repeat and must accumulate
Watch out for
- Writing
m[[0, 2], [1, 3]]expecting a 2x2 block and getting two elements.