Indexing, slicing and masks
Basic slicing, views versus copies, boolean masks and fancy indexing — plus the assignment rule that catches everyone.
Slicing returns views
A slice of an array is a view onto the same memory, not a copy. Changing the slice changes the original. .copy() breaks the link.
a = np.arange(10)
a[2:5] # array([2, 3, 4])
a[::-1] # reversed
a[::2] # every other element
v = a[0:3]
v[0] = 99
a[0] # 99 -> the slice was a view
c = a[0:3].copy()
c[0] = -1
a[0] # still 99m = np.arange(12).reshape(3, 4)
m[1, 2] # row 1, column 2
m[1] # entire row 1
m[:, 1] # entire column 1
m[0:2, 1:3] # block: rows 0-1, columns 1-2Boolean masks and fancy indexing
A comparison produces an array of booleans; using it as an index keeps the True positions. This is how filtering is meant to be written — no loops.
scores = np.array([88, 42, 95, 67, 71])
scores > 70 # array([ True, False, True, False, True])
scores[scores > 70] # array([88, 95, 71])
scores[(scores > 60) & (scores < 90)] # use & | ~ with parentheses
scores[scores < 70] = 0 # conditional assignment
np.where(scores > 70, "pass", "fail")idx = np.array([0, 2, 4])
scores[idx] # fancy indexing -> a COPY
scores[[0, 0, 1]] # duplicates allowed
np.argmax(scores) # index of the largest value
np.count_nonzero(scores > 70)⚠️
Fancy indexing (an integer array as index) returns a copy, while slicing returns a view. If you assign through a fancy index back to the array —
a[idx] += 1 — the behaviour is well defined, but assigning into a computed copy silently does nothing. When a change "does not stick", check whether you are working on a view or a copy.axis is a direction, not a row/column
axis=0 means "collapse the first dimension" — for a 2-D array, operate down the columns. Reading it as "rows" is what makes people get it backwards.
m = np.array([[1, 2, 3],
[4, 5, 6]])
m.sum() # 21 - everything
m.sum(axis=0) # array([5, 7, 9]) - one value per column
m.sum(axis=1) # array([ 6, 15]) - one value per row
m.mean(axis=0) # column meansFAQ
How do I test whether two arrays have the same values?
np.array_equal(a, b), or np.allclose(a, b) for floats where tiny rounding differences are expected. == gives you an array of booleans, not one answer.Why did a[idx] = value not change the original array?
Almost always because the array you modified was a temporary copy created by fancy indexing or a filtering expression. Assign to the original name, or use
np.put/boolean masks which do write through.Related
NumPy arrays Vectorised maths and broadcasting
Last refreshed 2026-09-18.