NumPy Indexing and Slicing
Indexing means picking one element; slicing means picking a range of elements. In 1D it works just like Python lists. In 2D and 3D, NumPy lets you write all positions inside one pair of brackets, separated by commas: sales[row, column].
How to run the examples
Create a new file named indexing_slicing.py in your NumpyTutorials folder (see the setup in lesson 01). Any name works; this one just matches the topic. Start the file with these lines:
import numpy as np
Then copy the examples of this page into the same file, one after another, in the order shown, and run it with python indexing_slicing.py (with your virtual environment active). Some examples use variables created in earlier ones, so keep everything in the one file. Each Output box shows what that example prints.
1. Indexing a 1D array
temps = np.array([21, 23, 25, 28, 30, 27, 24]) # Mon..Sun
# index: 0 1 2 3 4 5 6
# negative: -7 -6 -5 -4 -3 -2 -1
print("first temps[0] :", temps[0])
print("third temps[2] :", temps[2])
print("last temps[-1]:", temps[-1])
print("second last [-2]:", temps[-2])
try:
temps[7]
except IndexError as error:
print("Error:", error)
- Counting starts at 0:
temps[0]is the first value. - Negative indexes count from the end:
-1is the last value,-2the one before it. - An index that does not exist raises an
IndexError. With 7 elements the valid indexes are 0 to 6.
2. Slicing a 1D array: start:stop:step
print("temps[1:4] :", temps[1:4]) # index 1, 2, 3
print("temps[:3] :", temps[:3]) # first 3
print("temps[4:] :", temps[4:]) # from index 4 to the end
print("temps[-3:] :", temps[-3:]) # last 3
print("temps[::2] :", temps[::2]) # every 2nd
print("temps[::-1] :", temps[::-1]) # reversed
print("temps[1:6:2]:", temps[1:6:2]) # index 1, 3, 5
| Slice | Means |
|---|---|
[1:4] | from index 1 up to (not including) 4 |
[:3] | from the start: the first 3 |
[4:] | from index 4 to the end |
[-3:] | the last 3 |
[::2] | every 2nd element |
[::-1] | everything, reversed |
The stop value is never included. A simple way to remember: [a:b] gives you b - a elements.
3. Indexing a 2D array: [row, column]
Here sales is a table of 3 weeks (rows) x 4 days (columns):
sales = np.array([[10, 12, 14, 16], # week 0
[20, 22, 24, 26], # week 1
[30, 32, 34, 36]]) # week 2
# Mon Tue Wed Thu
print("sales[1, 2] :", sales[1, 2]) # week 1, Wednesday
print("sales[1][2] :", sales[1][2], "(works too, but slower)")
print("sales[-1, -1] :", sales[-1, -1]) # last week, last day
print("sales[0] :", sales[0], "(a whole row)")
sales[1, 2]means row 1, column 2: week 1, Wednesday.sales[1][2]gives the same value, but it first makes row 1 and then indexes it.[1, 2]is the NumPy way and is faster.- With only one index,
sales[0], you get the whole row.
4. Slicing a 2D array: [rows, columns]
Give a slice for the rows and a slice for the columns. A bare : means "all".
print("column 0 sales[:, 0] :", sales[:, 0])
print("last column sales[:, -1] :", sales[:, -1])
print("rows 0-1 sales[:2] :\n", sales[:2])
print("sub-table sales[1:, 1:3]:\n", sales[1:, 1:3])
print("every 2nd column sales[:, ::2]:\n", sales[:, ::2])
print("reversed rows sales[::-1]:\n", sales[::-1])
sales[:, 0]: all rows, column 0, so the whole first column.sales[:2]: the first 2 rows (all columns, because the column part is left out).sales[1:, 1:3]: rows from 1 to the end, columns 1 and 2. That is a smaller table cut out of the big one.- Steps work too:
[:, ::2]takes every 2nd column,[::-1]reverses the rows.
5. sales[0] vs sales[0:1]
A small detail that matters later:
print("sales[0] ->", sales[0], "shape", sales[0].shape) # an index removes the dimension
print("sales[0:1] ->", sales[0:1], "shape", sales[0:1].shape) # a slice keeps it
A plain index removes that dimension, so you get a 1D row of shape (4,). A slice keeps it, so you get a 2D table with one row, shape (1, 4). Both hold the same values, but they behave differently in maths and joining (lesson 08).
6. Indexing a 3D array: [table, row, column]
A 3D array is a stack of tables. Here it is 2 stores x 3 weeks x 4 days. np.arange(24).reshape(2, 3, 4) just fills it with 0 to 23 (lesson 06 explains reshape).
# 2 stores x 3 weeks x 4 days
stores = np.arange(24).reshape(2, 3, 4)
print(stores)
print("store 1 stores[1] :\n", stores[1])
print("store 0, week 2 stores[0, 2] :", stores[0, 2])
print("store 1, week 0, day 3 stores[1, 0, 3]:", stores[1, 0, 3])
print("day 0 of every week in every store stores[:, :, 0]:\n", stores[:, :, 0])
- One index picks a table:
stores[1]is the whole table of store 1. - Two indexes pick a row from a table, and three pick a single value.
stores[:, :, 0]takes column 0 from every row of every table: day 0 of every week in both stores.
7. Changing values
Indexes and slices can also appear on the left of = to change values:
marks = np.array([45, 67, 89, 32, 76, 58])
marks[3] = 40 # change one value
print("after marks[3] = 40 :", marks)
marks[:2] = 50 # one value into a whole slice
print("after marks[:2] = 50 :", marks)
marks[-2:] = [90, 95] # a list of the same length
print("after marks[-2:] = [...]:", marks)
grid = np.zeros((3, 4), dtype=int)
grid[1, :] = 7 # whole row 1
grid[:, 2] = 5 # whole column 2
print("grid:\n", grid)
- A single value assigned to a slice goes into every position of the slice (
marks[:2] = 50). - A list must have the same length as the slice.
- In 2D you can set a whole row (
grid[1, :] = 7) or a whole column (grid[:, 2] = 5) at once.
8. Real example: weekly sales
days = np.array(["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"])
week_sales = np.array([[120, 135, 128, 140, 180, 260, 240],
[110, 125, 138, 150, 190, 280, 255],
[130, 128, 142, 155, 200, 300, 270]])
print("Week 2 sales :", week_sales[1])
print("Saturdays :", week_sales[:, 5])
print("Weekend (Sat, Sun) :\n", week_sales[:, -2:])
print("Weekdays of last week :", dict(zip(days[:5].tolist(), week_sales[-1, :5].tolist())))
print("Weekend total per week :", week_sales[:, -2:].sum(axis=1))
With slicing you answer questions such as "all Saturdays" ([:, 5]), "the weekend of every week" ([:, -2:]) or "Monday to Friday of the last week" ([-1, :5]) in one short expression, without any loop.
Exercises
Try these exercises on your own before moving on:
- From np.arange(10, 101, 10) print the 3rd value, the last 4 values and the values in reverse order.
- From week_sales print Monday to Wednesday of the first two weeks.
- Set every Sunday in week_sales to 0.
- From np.arange(27).reshape(3, 3, 3) print the middle value (13).
Summary
- Indexes start at 0; negative indexes count from the end.
- Slices are
start:stop:step, and the stop is not included. - In 2D use
arr[row, column];:means "all", soarr[:, 0]is a column. - An index removes a dimension; a slice keeps it.
- 3D arrays use
arr[table, row, column]. - Assigning to an index or slice changes the array; one value fills the whole slice.