2D Slicing: Rows, Columns & Sub-matrices
Slice each axis of a 2D array separately to get columns, groups of rows, sub-tables and stepped grids.
"All players' scores in match 1", "the first two players", "Virat and Rohit in matches 1–4" — each of these is a rectangular piece of the scores table. In NumPy you cut such pieces by putting a slice on each axis.
Definition
2D slicing selects a rectangular region of a 2D array by giving a slice (or index) for each axis:
arr[row_slice, col_slice]. Each slice follows the usualstart:stop:steprules, and a bare colon:means "every position on this axis". The result is a view of the original array.
- Slice per axis — rows and columns are sliced independently;
arr[0:2, 0:4]means rows 0–1 and columns 0–3. - Bare colon
:— "take all rows" or "take all columns". - Index vs slice on an axis — an integer removes that axis (result has fewer dimensions); a slice keeps it, even if it selects only one position.
- View — no data is copied; editing the result edits
scores.
Syntax
python
arr[r1:r2, c1:c2] # sub-matrix: rows r1..r2-1, columns c1..c2-1
arr[:, c] # column c (1D)
arr[:, c:c+1] # column c kept as a 2D column (shape (rows, 1))
arr[r1:r2] # some rows, all columns (same as arr[r1:r2, :])
arr[:, ::2] # every other column
arr[::-1, :] # rows in reverse order| Part | Meaning | Default |
|---|---|---|
row_slice | which rows (axis 0): start:stop:step | : (all rows) |
col_slice | which columns (axis 1): start:stop:step | : (all columns) — may be omitted |
Example — columns and groups of rows
python
import numpy as np
scores = np.array([
[72, 45, 88, 31, 64, 0, 103, 52], # row 0: Virat
[56, 0, 74, 88, 32, 45, 61, 17], # row 1: Rohit
[45, 32, 0, 67, 18, 54, 78, 22], # row 2: Hardik
])
print("Match 1, all players :", scores[:, 0])
print("Last match, all :", scores[:, -1])
print("First two players:")
print(scores[:2])
print("Matches 3-5 of all players:")
print(scores[:, 2:5])text
Match 1, all players : [72 56 45]
Last match, all : [52 17 22]
First two players:
[[ 72 45 88 31 64 0 103 52]
[ 56 0 74 88 32 45 61 17]]
Matches 3-5 of all players:
[[88 31 64]
[74 88 32]
[ 0 67 18]]How it works: scores[:, 0] = every row, column 0 → one score per player. scores[:2] slices only axis 0, so all 8 columns come along. scores[:, 2:5] keeps all rows but only columns 2, 3, 4.
Example — sub-matrix and stepped slices
python
scores = np.array([
[72, 45, 88, 31, 64, 0, 103, 52], # row 0: Virat
[56, 0, 74, 88, 32, 45, 61, 17], # row 1: Rohit
[45, 32, 0, 67, 18, 54, 78, 22], # row 2: Hardik
])
print("Virat & Rohit, matches 1-4:")
print(scores[0:2, 0:4])
print("Every other match, all players:")
print(scores[:, ::2])
print("Players in reverse order, last 3 matches:")
print(scores[::-1, -3:])text
Virat & Rohit, matches 1-4:
[[72 45 88 31]
[56 0 74 88]]
Every other match, all players:
[[ 72 88 64 103]
[ 56 74 32 61]
[ 45 0 18 78]]
Players in reverse order, last 3 matches:
[[ 54 78 22]
[ 45 61 17]
[ 0 103 52]]How it works: 0:2 on rows and 0:4 on columns cut out a 2×4 block. ::2 on columns picks columns 0, 2, 4, 6. ::-1 on rows flips the player order.
Example — integer vs slice changes the shape
python
scores = np.array([
[72, 45, 88, 31, 64, 0, 103, 52], # row 0: Virat
[56, 0, 74, 88, 32, 45, 61, 17], # row 1: Rohit
[45, 32, 0, 67, 18, 54, 78, 22], # row 2: Hardik
])
print(scores[1, :].shape) # integer on axis 0 -> row as 1D
print(scores[1:2, :].shape) # slice on axis 0 -> stays 2D
print(scores[:, 0].shape) # integer on axis 1 -> column as 1D
print(scores[:, 0:1].shape) # slice on axis 1 -> column as 2D
print(scores[:, 0:1])text
(8,)
(1, 8)
(3,)
(3, 1)
[[72]
[56]
[45]]How it works: an integer index "uses up" its axis, so a column taken with [:, 0] is a flat 1D array of 3 values. A slice 0:1 keeps the axis with length 1, giving a 3×1 column vector — useful later for broadcasting.
Quick reference
| Goal | Expression | Result shape (from (3, 8)) |
|---|---|---|
| One cell | scores[1, 2] | scalar |
| One row | scores[1] / scores[1, :] | (8,) |
| One column | scores[:, 2] | (3,) |
| Column kept 2D | scores[:, 2:3] | (3, 1) |
| First 2 rows | scores[:2] | (2, 8) |
| Sub-matrix | scores[0:2, 0:4] | (2, 4) |
| Every other column | scores[:, ::2] | (3, 4) |
| Whole array reversed both ways | scores[::-1, ::-1] | (3, 8) |
Common mistakes
- ❌
scores[0:2][0:4]for a sub-matrix. ✅ That slices rows twice (rows 0–1, then rows 0–1 of those). Usescores[0:2, 0:4]. - ❌ Expecting
scores[:, 0]to be a 3×1 column. ✅ It is 1D(3,); usescores[:, 0:1](orscores[:, [0]]) to keep 2D. - ❌ Forgetting
stopis excluded on each axis:scores[0:1, 0:1]is a 1×1 array, not 2×2. - ❌ Editing a slice "to try something" and being surprised that
scoreschanged. ✅ Slices are views — call.copy()first.
Interview tip
Q: What is the difference between arr[:, 0] and arr[:, [0]]?
A: arr[:, 0] uses an integer, so the column axis disappears → shape (rows,), a view. arr[:, [0]] uses a list (fancy indexing), so the axis stays → shape (rows, 1), and it is a copy.
Key points to remember
- 2D slicing gives one slice per axis: arr[row_slice, col_slice]; each follows start:stop:step.
- A bare colon : means 'all positions on this axis'; arr[:, c] is column c, arr[r1:r2] is a group of rows.
- arr[r1:r2, c1:c2] cuts out a rectangular sub-matrix.
- An integer on an axis removes that axis (fewer dimensions); a slice keeps it — arr[:, 0] is (rows,), arr[:, 0:1] is (rows, 1).
- arr[0:2][0:4] is NOT a sub-matrix — it slices rows twice; use the comma form.
- Slices of 2D arrays are views — changes write back into the original.
Try it yourself
Columns, rows and a sub-matrix
Shape changes: index vs slice
Practice: last 3 matches of the top 2 players
Revision Flashcards
Tap a card to flip it and see the answer.
