π NumPy Indexing & Slicing: Finding Things in Your Treasure Chest
Imagine you have a treasure chest with many compartments. Each compartment holds a gem. To find a specific gem, you need to know where it lives in the chest.
Thatβs exactly what indexing and slicing do in NumPy! They help you find and grab data from your arrays.
π― The Big Picture
| What You Want | What to Use |
|---|---|
| One item | Indexing |
| Many items in a row | Slicing |
| Skip some items | Step |
π Positive Indexing: Counting From the Front Door
Think of a row of houses on a street. The first house is number 0, the next is 1, and so on.
import numpy as np
gems = np.array(['Ruby', 'Emerald', 'Diamond', 'Sapphire'])
# 0 1 2 3
print(gems[0]) # Ruby
print(gems[2]) # Diamond
Remember: Python starts counting from 0, not 1!
graph TD A["gems array"] --> B["Index 0: Ruby"] A --> C["Index 1: Emerald"] A --> D["Index 2: Diamond"] A --> E["Index 3: Sapphire"]
π Negative Indexing: Counting From the Back Door
What if you want the last gem but donβt know how many gems there are?
Use negative numbers! They count from the end.
- -1 = last item
- -2 = second-to-last
- -3 = third-to-last
gems = np.array(['Ruby', 'Emerald', 'Diamond', 'Sapphire'])
# -4 -3 -2 -1
print(gems[-1]) # Sapphire (last)
print(gems[-2]) # Diamond (second-to-last)
Super useful when you just want βthe last oneβ without counting!
π’ Multi-Dimensional Indexing: Finding Rooms in a Building
A 2D array is like a building with floors and rooms.
- First number = which floor (row)
- Second number = which room (column)
building = np.array([
[101, 102, 103], # Floor 0
[201, 202, 203], # Floor 1
[301, 302, 303] # Floor 2
])
print(building[1, 2]) # 203
# Floor 1, Room 2
graph TD A["building[1, 2]"] --> B["Go to Floor 1"] B --> C["Go to Room 2"] C --> D["Found: 203"]
Mix positive and negative too!
print(building[0, -1]) # 103
# Floor 0, last room
β¨ Ellipsis: The Magic Shortcut
When you have many dimensions, typing all those commas gets tiring.
The ellipsis (...) means βfill in whatever I skipped.β
cube = np.array([
[[1, 2], [3, 4]],
[[5, 6], [7, 8]]
])
# These are the same:
print(cube[0, :, :]) # Explicit
print(cube[0, ...]) # With ellipsis
# Both give: [[1, 2], [3, 4]]
Think of ... as saying βand all the rest.β
βοΈ Basic Slicing: Grabbing a Range
Slicing lets you grab multiple items at once.
Syntax: array[start:stop]
- start = where to begin (included)
- stop = where to end (NOT included)
numbers = np.array([10, 20, 30, 40, 50, 60])
print(numbers[1:4]) # [20, 30, 40]
# Starts at index 1, stops BEFORE index 4
graph LR A["[10, 20, 30, 40, 50, 60]"] --> B["numbers[1:4]"] B --> C["[20, 30, 40]"]
Shortcuts:
numbers[:3] # [10, 20, 30] - from start
numbers[3:] # [40, 50, 60] - to end
numbers[:] # Everything!
π¦ Slicing with Step: Skip Like a Kangaroo
Want to grab every other item? Add a step!
Syntax: array[start:stop:step]
numbers = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
print(numbers[::2]) # [0, 2, 4, 6, 8]
# Every 2nd item
print(numbers[1::2]) # [1, 3, 5, 7, 9]
# Every 2nd, starting from index 1
print(numbers[::3]) # [0, 3, 6, 9]
# Every 3rd item
Reverse an array with step -1:
print(numbers[::-1]) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
π’ Multi-Dimensional Slicing: Slicing the Building
Apply slicing to each dimension separately!
grid = np.array([
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]
])
# Get rows 0-1, columns 1-2
print(grid[0:2, 1:3])
# [[2, 3],
# [6, 7]]
# All rows, every other column
print(grid[:, ::2])
# [[1, 3],
# [5, 7],
# [9, 11]]
graph TD A["grid[0:2, 1:3]"] --> B["Rows 0 to 2"] B --> C["Columns 1 to 3"] C --> D["Result: 2x2 block"]
π§ͺ Real-World Example
Imagine you have test scores for 4 students across 5 tests:
scores = np.array([
[85, 90, 78, 92, 88], # Student 0
[79, 85, 90, 87, 91], # Student 1
[92, 88, 84, 90, 86], # Student 2
[76, 82, 79, 85, 88] # Student 3
])
# Last test for everyone
print(scores[:, -1]) # [88, 91, 86, 88]
# First 2 students, first 3 tests
print(scores[:2, :3])
# [[85, 90, 78],
# [79, 85, 90]]
# Every other student, all tests
print(scores[::2, :])
# [[85, 90, 78, 92, 88],
# [92, 88, 84, 90, 86]]
π Quick Summary
| Technique | Syntax | Example |
|---|---|---|
| Positive index | arr[i] |
arr[0] β first |
| Negative index | arr[-i] |
arr[-1] β last |
| 2D index | arr[row, col] |
arr[1, 2] |
| Ellipsis | arr[i, ...] |
Shortcut for remaining dims |
| Basic slice | arr[start:stop] |
arr[1:4] |
| Step slice | arr[start:stop:step] |
arr[::2] |
| 2D slice | arr[r1:r2, c1:c2] |
arr[:2, 1:3] |
π‘ Remember This!
- Indexing starts at 0 β always!
- Negative indices count backward β
-1is the last - Slicing excludes the stop β
[1:4]gives indices 1, 2, 3 - Step lets you skip β
[::2]grabs every other - Ellipsis = βand all the restβ β saves typing in many dimensions
You now have the keys to unlock any treasure in your NumPy arrays! ποΈ