Skip to main content

Python NumPy: How to Access Different Rows of a Multidimensional NumPy Array in Python

When working with multidimensional NumPy arrays, you frequently need to access specific rows - whether it's the first row, the last two rows, middle rows, or a combination of non-contiguous rows. NumPy provides powerful indexing and slicing syntax that makes row selection intuitive and efficient.

This guide covers how to access rows in 2D and 3D arrays using slicing, fancy indexing, and combined row-column selection.

Accessing Rows in a 2D Array

Selecting a Single Row

Use a single index to access one row:

import numpy as np

arr = np.array([
[10, 20, 30],
[40, 50, 60],
[70, 80, 90]
])

# First row
print("First row:", arr[0])

# Last row
print("Last row:", arr[-1])

# Middle row (index 1)
print("Middle row:", arr[1])

Output:

First row: [10 20 30]
Last row: [70 80 90]
Middle row: [40 50 60]

Selecting Multiple Rows with Slicing

Use the start:stop:step syntax to select a range of rows:

import numpy as np

arr = np.array([
[10, 20, 30],
[40, 50, 60],
[70, 80, 90],
[100, 110, 120]
])

# First two rows
print("First 2 rows:\n", arr[:2])

# Last two rows
print("Last 2 rows:\n", arr[-2:])

# Every other row
print("Every other row:\n", arr[::2])

Output:

First 2 rows:
[[10 20 30]
[40 50 60]]
Last 2 rows:
[[ 70 80 90]
[100 110 120]]
Every other row:
[[ 10 20 30]
[ 70 80 90]]

Selecting Non-Contiguous Rows (Fancy Indexing)

To select specific rows that aren't adjacent, pass a list of indices:

import numpy as np

arr = np.array([
[10, 20, 30],
[40, 50, 60],
[70, 80, 90],
[100, 110, 120]
])

# Select the first and last rows
selected = arr[[0, 3]]
print("First and last rows:\n", selected)

# Select rows 0, 2 (every other row, but explicitly)
selected = arr[[0, 2]]
print("Rows 0 and 2:\n", selected)

Output:

First and last rows:
[[ 10 20 30]
[100 110 120]]
Rows 0 and 2:
[[10 20 30]
[70 80 90]]
Slicing vs Fancy Indexing
  • Slicing (arr[1:3]) - selects a contiguous range and returns a view (shares memory with the original).
  • Fancy indexing (arr[[0, 2]]) - selects arbitrary rows and returns a copy (independent of the original).
import numpy as np

arr = np.array([[1, 2], [3, 4], [5, 6]])

# Slicing: view (modifications affect original)
view = arr[0:2]
view[0, 0] = 99
print("Original after slice modification:", arr[0, 0]) # 99

# Fancy indexing: copy (modifications don't affect original)
arr = np.array([[1, 2], [3, 4], [5, 6]])
copy = arr[[0, 1]]
copy[0, 0] = 99
print("Original after fancy index modification:", arr[0, 0]) # 1

Output:

Original after slice modification: 99
Original after fancy index modification: 1

Selecting Specific Rows AND Columns

Combine row and column indexing to extract a sub-matrix:

import numpy as np

arr = np.array([
[12, 15, 18],
[25, 30, 35],
[40, 45, 50]
])

# First 2 rows, first 2 columns
sub = arr[:2, :2]
print("Sub-matrix:\n", sub)

# Last row, last 2 columns
sub = arr[-1, -2:]
print("Last row, last 2 cols:", sub)

# Rows 0 and 2, column 1 only
sub = arr[[0, 2], 1]
print("Rows 0,2 column 1:", sub)

Output:

Sub-matrix:
[[12 15]
[25 30]]
Last row, last 2 cols: [45 50]
Rows 0,2 column 1: [15 45]

Accessing Rows in a 3D Array

A 3D array can be thought of as a collection of 2D matrices (or "slices"). The dimensions are typically: [slice, row, column].

import numpy as np

arr = np.array([
[[10, 25, 70],
[30, 45, 55],
[20, 45, 7]],

[[50, 65, 8],
[70, 85, 10],
[11, 22, 33]]
])

print("Shape:", arr.shape) # (2, 3, 3) → 2 slices, 3 rows, 3 columns

Output:

Shape: (2, 3, 3)

Selecting a Row Across All Slices

Use : for the first dimension to select from all slices, then specify the row index:

import numpy as np

arr = np.array([
[[10, 25, 70],
[30, 45, 55],
[20, 45, 7]],

[[50, 65, 8],
[70, 85, 10],
[11, 22, 33]]
])

# Middle row (index 1) from all slices
middle_rows = arr[:, 1]
print("Middle row from each slice:\n", middle_rows)

Output:

Middle row from each slice:
[[30 45 55]
[70 85 10]]

Selecting Multiple Rows Across All Slices

import numpy as np

arr = np.array([
[[10, 25, 70],
[30, 45, 55],
[20, 45, 7]],

[[50, 65, 8],
[70, 85, 10],
[11, 22, 33]]
])

# First and last rows from all slices
selected = arr[:, [0, 2]]
print("First and last rows from each slice:\n", selected)

Output:

First and last rows from each slice:
[[[10 25 70]
[20 45 7]]

[[50 65 8]
[11 22 33]]]

Selecting Specific Rows and Columns in 3D

import numpy as np

arr = np.array([
[[ 5, 10, 15],
[20, 25, 30],
[35, 40, 45]],

[[ 2, 4, 6],
[ 8, 10, 12],
[14, 16, 18]],

[[ 7, 14, 21],
[28, 35, 42],
[49, 56, 63]]
])

# First 2 rows and first 2 columns from each slice
sub = arr[:, :2, :2]
print("Sub-arrays:\n", sub)

Output:

Sub-arrays:
[[[ 5 10]
[20 25]]

[[ 2 4]
[ 8 10]]

[[ 7 14]
[28 35]]]

Conditional Row Selection

Select rows based on a condition applied to the data:

import numpy as np

arr = np.array([
[10, 20, 30],
[40, 50, 60],
[5, 15, 25],
[70, 80, 90]
])

# Select rows where the first column value is greater than 20
mask = arr[:, 0] > 20
selected = arr[mask]

print("Rows where first column > 20:\n", selected)

Output:

Rows where first column > 20:
[[40 50 60]
[70 80 90]]

This is especially useful for filtering data based on specific criteria.

Quick Reference

TaskSyntaxExample
Single rowarr[i]arr[2]
Row rangearr[start:stop]arr[1:3]
Last N rowsarr[-N:]arr[-2:]
Every Nth rowarr[::N]arr[::2]
Specific rowsarr[[i, j, k]]arr[[0, 2, 4]]
Rows + columnsarr[rows, cols]arr[:2, :2]
3D: row across slicesarr[:, i]arr[:, 1]
Conditional rowsarr[condition]arr[arr[:, 0] > 20]

Conclusion

NumPy's indexing and slicing syntax makes accessing rows in multidimensional arrays both intuitive and efficient.

  • Use slicing (arr[1:3]) for contiguous row ranges, fancy indexing (arr[[0, 2]]) for non-contiguous selections, and boolean masks for conditional filtering.
  • For 3D arrays, remember the dimension order is [slice, row, column] and use : to select across all elements of a dimension.

Understanding the difference between views (from slicing) and copies (from fancy indexing) helps you write correct and performant code.