Indexing & Slicing
Definition
NumPy supports several indexing styles: basic slicing (returns a view), fancy indexing (integer arrays, returns a copy), and boolean indexing (masks, returns a copy). Knowing which returns a view vs a copy is essential to avoid unexpected mutation bugs.
Basic Indexing & Slicing
arr = np.array([10, 20, 30, 40, 50])
arr[0] # 10 β single element
arr[-1] # 50 β last element
arr[1:4] # [20, 30, 40] β slice, exclusive of end
arr[::2] # [10, 30, 50] β every 2nd element
arr[::-1] # [50, 40, 30, 20, 10] β reversed2D Indexing
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
arr2d[0, 1] # 2 β row 0, col 1
arr2d[1] # [4, 5, 6] β entire row 1
arr2d[:, 1] # [2, 5, 8] β entire column 1
arr2d[0:2, 1:3] # sub-matrix, rows 0-1, cols 1-2
arr2d[:, ::-1] # reverse column orderViews vs Copies
sub = arr2d[0:2, 0:2] # a VIEW β shares memory with arr2d
sub[0, 0] = 999 # modifies arr2d too!
sub_copy = arr2d[0:2, 0:2].copy() # explicit COPY β independentBasic slicing returns a view, not a copy
Modifying a sliced view modifies the original array. Use
.copy()explicitly whenever you need an independent array. Fancy indexing and boolean indexing, by contrast, always return copies.
Fancy Indexing (Integer Arrays)
arr = np.array([10, 20, 30, 40, 50])
arr[[0, 2, 4]] # [10, 30, 50] β select specific positions
arr[[0, 0, 1]] # [10, 10, 20] β repeats allowed
arr2d[[0, 2]] # select rows 0 and 2
arr2d[[0, 1], [1, 2]] # elements at (0,1) and (1,2) β paired coordinates -> [2, 6]
arr2d[:, [0, 2]] # select columns 0 and 2Fancy indexing with paired arrays selects coordinates, not a sub-grid
arr2d[[0,1],[1,2]]picks(0,1)and(1,2)specifically β not the 2x2 block. Usenp.ix_()if you want the cross-product (sub-grid) instead:arr2d[np.ix_([0,1],[1,2])].
Boolean Indexing (Masking)
arr = np.array([1, -2, 3, -4, 5])
mask = arr > 0
arr[mask] # [1, 3, 5] β keep only positive values
arr[arr > 0] = 0 # set all positive values to 0 (in-place)
arr2d[arr2d > 5] # flattens result to 1D β matches only
# Combining conditions β must use & | ~ with parentheses (not and/or/not)
arr[(arr > 0) & (arr < 4)]See 08-Boolean-Masking-Where for
np.where,np.select, and further conditional-logic patterns.
Ellipsis (...) and np.newaxis
arr4d = np.zeros((2, 3, 4, 5))
arr4d[0, ..., 0] # equivalent to arr4d[0, :, :, 0] β "..." fills remaining dims
arr = np.array([1, 2, 3])
arr[:, np.newaxis] # shape (3,) -> (3, 1), adds a new axis
arr[np.newaxis, :] # shape (3,) -> (1, 3)Setting Values via Indexing
arr[0] = 100
arr[1:3] = [200, 300]
arr2d[:, 0] = 0 # set entire column to 0
arr[arr < 0] = 0 # clip negatives to 0 via boolean masknp.take and np.put
np.take(arr, [0, 2, 4]) # equivalent to fancy indexing, but works with axis= for ND arrays
np.put(arr, [0, 1], [99, 98]) # equivalent to arr[[0,1]] = [99, 98], modifies in place