Selecting parts of arrays is in almost every line of numerical code, and slices are free because they are views.
Indexing a 1-D array works like a list: a[0], a[-1], a[2:5], a[::2]. Multi-dimensional arrays take one index per axis, separated by commas: m[1, 2] is row 1, column 2. Prefer this over m[1][2], which first builds a row and then indexes it.
Each position can be an integer or a slice:
m[0]orm[0, :]: the first row (shape drops by one dimension)m[:, 1]: the second column, as a 1-D arraym[1:, :2]: rows from 1 on, first two columns, still 2-Dm[..., 0]: the ellipsis stands for "all remaining axes", useful for arrays like images of shape(h, w, 3)
An integer index removes that axis; a slice keeps it, even if it's length 1. So m[:, 1] has shape (rows,) while m[:, 1:2] has shape (rows, 1).
The big difference from lists: a slice of an ndarray is a view, not a copy. Modifying sub = m[:2, :2] modifies m. This lets you work on a window of a big array without copying, but can surprise you if you expected independence. Use .copy() when you need a separate array.
You can also assign through indexes: m[0] = 0 sets a whole row, and m[:, 1] = [7, 8, 9] writes a column. The right side must match or broadcast to the selected shape.
Example
import numpy as np
m = np.arange(12).reshape(3, 4)
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
print(m[1, 2]) # 6
print(m[:, 1]) # [1 5 9] shape (3,)
print(m[:, 1:2].shape) # (3, 1)
print(m[1:, :2]) # [[4 5] [8 9]]
print(m[::2, ::-1]) # rows 0 and 2, columns reversed
sub = m[:2, :2] # a view
sub[:] = 0
print(m[0]) # [0 0 2 3] -- original changed
safe = m[:, 0].copy()
m[:, 0] = [7, 8, 9] # assign a column
print(safe, m[:, 0]) # [0 0 8] [7 8 9]Remember
- Use one comma-separated index per axis:
m[r, c] - Integers drop an axis, slices keep it
- Slices are views: writing to them changes the original
- Call
.copy()when you need an independent piece
Watch out for
- Expecting
b = a[2:5]to be a copy as with lists, then being surprised when changingbchangesa.