Skip to content

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)
Output
first  temps[0] : 21
third  temps[2] : 25
last   temps[-1]: 24
second last [-2]: 27
Error: index 7 is out of bounds for axis 0 with size 7
  • Counting starts at 0: temps[0] is the first value.
  • Negative indexes count from the end: -1 is the last value, -2 the 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
Output
temps[1:4]  : [23 25 28]
temps[:3]   : [21 23 25]
temps[4:]   : [30 27 24]
temps[-3:]  : [30 27 24]
temps[::2]  : [21 25 30 24]
temps[::-1] : [24 27 30 28 25 23 21]
temps[1:6:2]: [23 28 27]
SliceMeans
[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)")
Output
sales[1, 2]   : 24
sales[1][2]   : 24 (works too, but slower)
sales[-1, -1] : 36
sales[0]      : [10 12 14 16] (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])
Output
column 0     sales[:, 0]  : [10 20 30]
last column  sales[:, -1] : [16 26 36]
rows 0-1     sales[:2]    :
 [[10 12 14 16]
 [20 22 24 26]]
sub-table    sales[1:, 1:3]:
 [[22 24]
 [32 34]]
every 2nd column sales[:, ::2]:
 [[10 14]
 [20 24]
 [30 34]]
reversed rows sales[::-1]:
 [[30 32 34 36]
 [20 22 24 26]
 [10 12 14 16]]
  • 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
Output
sales[0]   -> [10 12 14 16] shape (4,)
sales[0:1] -> [[10 12 14 16]] shape (1, 4)

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])
Output
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]
store 1          stores[1]        :
 [[12 13 14 15]
 [16 17 18 19]
 [20 21 22 23]]
store 0, week 2  stores[0, 2]     : [ 8  9 10 11]
store 1, week 0, day 3 stores[1, 0, 3]: 15
day 0 of every week in every store stores[:, :, 0]:
 [[ 0  4  8]
 [12 16 20]]
  • 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)
Output
after marks[3] = 40     : [45 67 89 40 76 58]
after marks[:2] = 50    : [50 50 89 40 76 58]
after marks[-2:] = [...]: [50 50 89 40 90 95]
grid:
 [[0 0 5 0]
 [7 7 5 7]
 [0 0 5 0]]
  • 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))
Output
Week 2 sales           : [110 125 138 150 190 280 255]
Saturdays              : [260 280 300]
Weekend (Sat, Sun)     :
 [[260 240]
 [280 255]
 [300 270]]
Weekdays of last week  : {'Mon': 130, 'Tue': 128, 'Wed': 142, 'Thu': 155, 'Fri': 200}
Weekend total per week : [500 535 570]

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:

  1. From np.arange(10, 101, 10) print the 3rd value, the last 4 values and the values in reverse order.
  2. From week_sales print Monday to Wednesday of the first two weeks.
  3. Set every Sunday in week_sales to 0.
  4. 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", so arr[:, 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.

Next: Lesson 05: Boolean Masks, Fancy Indexing, np.where.