Python NumPy: How to Access and Slice NumPy Arrays in Python (1D, 2D, 3D Arrays)
Efficient data manipulation in data science depends heavily on mastering array indexing and slicing. NumPy provides powerful capabilities that extend far beyond standard Python lists, enabling you to extract, modify, and filter data with concise syntax.
1D Array Indexing
Accessing elements in a 1D array works similarly to Python lists, with support for positive indices, negative indices, and slicing.
import numpy as np
arr = np.array([10, 20, 30, 40, 50])
# Positive indexing (from start)
print(arr[0]) # 10
print(arr[2]) # 30
# Negative indexing (from end)
print(arr[-1]) # 50
print(arr[-2]) # 40
# Slicing [start:end:step]
print(arr[1:4]) # [20 30 40]
print(arr[:3]) # [10 20 30]
print(arr[2:]) # [30 40 50]
print(arr[::2]) # [10 30 50] (every 2nd element)
print(arr[::-1]) # [50 40 30 20 10] (reversed)
Output:
10
30
50
40
[20 30 40]
[10 20 30]
[30 40 50]
[10 30 50]
[50 40 30 20 10]
Modifying Elements
import numpy as np
arr = np.array([10, 20, 30, 40, 50])
# Modify single element
arr[0] = 100
print(arr) # [100 20 30 40 50]
# Modify slice
arr[1:3] = [200, 300]
print(arr) # [100 200 300 40 50]
Output:
[100 20 30 40 50]
[100 200 300 40 50]
2D Array Indexing (Matrices)
A 2D array organizes data in rows and columns. Access elements using the syntax array[row, column].
import numpy as np
matrix = np.array([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
])
# Single element: row 1, column 2
print(matrix[1, 2]) # 6
# Alternative syntax (less preferred)
print(matrix[1][2]) # 6
# Negative indices work too
print(matrix[-1, -1]) # 9
Output:
6
6
9
Row and Column Selection
import numpy as np
matrix = np.array([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
])
# Entire row (all columns)
print(matrix[0, :]) # [1 2 3]
print(matrix[0]) # [1 2 3] (shorthand)
# Entire column (all rows)
print(matrix[:, 1]) # [2 5 8]
# Multiple rows
print(matrix[0:2, :])
# [[1 2 3]
# [4 5 6]]
# Multiple columns
print(matrix[:, 1:3])
# [[2 3]
# [5 6]
# [8 9]]
Output:
[1 2 3]
[1 2 3]
[2 5 8]
[[1 2 3]
[4 5 6]]
[[2 3]
[5 6]
[8 9]]
Submatrix Extraction
import numpy as np
matrix = np.array([
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16]
])
# Extract 2x2 submatrix from center
submatrix = matrix[1:3, 1:3]
print(submatrix)
# [[ 6 7]
# [10 11]]
# Every other row and column
print(matrix[::2, ::2])
# [[ 1 3]
# [ 9 11]]
Output:
[[ 6 7]
[10 11]]
[[ 1 3]
[ 9 11]]
Use the comma-separated syntax matrix[row, col] instead of chained brackets matrix[row][col]. The comma syntax is more efficient and clearer.
3D Array Indexing (Tensors)
Think of 3D arrays as stacks of 2D matrices-like layers in a cake or frames in a video. Access elements using array[layer, row, column].
import numpy as np
# Shape: (2, 3, 4) (2 layers, 3 rows, 4 columns)
tensor = np.array([
# Layer 0
[[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]],
# Layer 1
[[13, 14, 15, 16],
[17, 18, 19, 20],
[21, 22, 23, 24]]
])
print(f"Shape: {tensor.shape}") # (2, 3, 4)
# Access entire layer
print(tensor[0])
# [[ 1 2 3 4]
# [ 5 6 7 8]
# [ 9 10 11 12]]
# Single element: layer 1, row 0, column 2
print(tensor[1, 0, 2]) # 15
# Row across specific layer
print(tensor[1, 0, :]) # [13 14 15 16]
# Column across all layers
print(tensor[:, :, 0])
# [[ 1 5 9]
# [13 17 21]]
Output:
Shape: (2, 3, 4)
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]
15
[13 14 15 16]
[[ 1 5 9]
[13 17 21]]
Practical 3D Example: RGB Image
import numpy as np
# Simulated 4x4 RGB image (height, width, channels)
image = np.random.randint(0, 256, size=(4, 4, 3))
print(f"Image shape: {image.shape}")
# Get single pixel (row 0, col 0), returns [R, G, B]
pixel = image[0, 0]
print(f"Pixel RGB: {pixel}")
# Get only the red channel
red_channel = image[:, :, 0]
print(f"Red channel shape: {red_channel.shape}")
# Get top-left 2x2 region, all channels
region = image[:2, :2, :]
print(f"Region shape: {region.shape}")
Output:
Image shape: (4, 4, 3)
Pixel RGB: [ 35 191 34]
Red channel shape: (4, 4)
Region shape: (2, 2, 3)
Boolean Indexing (Filtering)
Boolean indexing is one of NumPy's most powerful features. Apply conditions to select elements that match specific criteria.
import numpy as np
arr = np.array([10, 15, 20, 25, 30])
# Create boolean mask
mask = arr > 20
print(mask) # [False False False True True]
# Apply mask to filter
filtered = arr[mask]
print(filtered) # [25 30]
# Shorthand: combine in one step
print(arr[arr > 20]) # [25 30]
Output:
[False False False True True]
[25 30]
[25 30]
Multiple Conditions
import numpy as np
arr = np.array([5, 10, 15, 20, 25, 30])
# AND condition: between 10 and 25
result = arr[(arr >= 10) & (arr <= 25)]
print(result) # [10 15 20 25]
# OR condition: less than 10 or greater than 25
result = arr[(arr < 10) | (arr > 25)]
print(result) # [ 5 30]
# NOT condition
result = arr[~(arr == 15)]
print(result) # [ 5 10 20 25 30]
Output:
[10 15 20 25]
[ 5 30]
[ 5 10 20 25 30]
Use & for AND, | for OR, and ~ for NOT with NumPy arrays. The Python keywords and, or, not don't work with array conditions. Always wrap individual conditions in parentheses.
Boolean Indexing with 2D Arrays
import numpy as np
matrix = np.array([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
])
# Find all values greater than 5
print(matrix[matrix > 5]) # [6 7 8 9], returns 1D array
# Replace values based on condition
matrix[matrix > 5] = 0
print(matrix)
# [[1 2 3]
# [4 5 0]
# [0 0 0]]
Output:
[6 7 8 9]
[[1 2 3]
[4 5 0]
[0 0 0]]
Fancy Indexing (Index Arrays)
Use arrays of indices to access multiple specific elements:
import numpy as np
arr = np.array([10, 20, 30, 40, 50])
# Access elements at indices 0, 2, and 4
indices = [0, 2, 4]
print(arr[indices]) # [10 30 50]
# 2D fancy indexing
matrix = np.array([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
])
# Get elements at (0,0), (1,1), (2,2), diagonal
rows = [0, 1, 2]
cols = [0, 1, 2]
print(matrix[rows, cols]) # [1 5 9]
Output:
[10 30 50]
[1 5 9]
Views vs Copies
Understanding when NumPy creates views versus copies is crucial for avoiding bugs:
import numpy as np
arr = np.array([1, 2, 3, 4, 5])
# Slicing creates a VIEW (shares memory)
view = arr[1:4]
view[0] = 99
print(arr) # [ 1 99 3 4 5] (original changed!)
# Fancy indexing creates a COPY
arr = np.array([1, 2, 3, 4, 5])
copy = arr[[1, 2, 3]]
copy[0] = 99
print(arr) # [1 2 3 4 5] (original unchanged)
# Force a copy explicitly
arr = np.array([1, 2, 3, 4, 5])
explicit_copy = arr[1:4].copy()
explicit_copy[0] = 99
print(arr) # [1 2 3 4 5] (original unchanged)
Output:
[ 1 99 3 4 5]
[1 2 3 4 5]
[1 2 3 4 5]
Slices create views that share memory with the original array. Modifying a slice modifies the original. Use .copy() when you need an independent copy.
Summary
| Dimension | Syntax | Description |
|---|---|---|
| 1D | arr[i] | Single element by index |
| 1D slice | arr[start:end:step] | Range of elements |
| 2D | arr[row, col] | Single element in matrix |
| 2D row | arr[row, :] | Entire row |
| 2D column | arr[:, col] | Entire column |
| 3D | arr[layer, row, col] | Single element in tensor |
| Boolean | arr[arr > 5] | Filter by condition |
| Fancy | arr[[0, 2, 4]] | Multiple specific indices |
Mastering these indexing techniques allows you to efficiently extract, transform, and analyze data without writing explicit loops-a cornerstone of effective NumPy programming.