Contents

Python NumPy For Your Grandma - 2.5 Indexing Multidimensional Arrays

In this section, we’ll see how to index and modify multidimensional arrays.

We’ll start by making a new three by four array called bar from a list of lists.

import numpy as np
bar = np.array([
    [5, 10, 15, 20],
    [25, 30, 35, 40],
    [45, 50, 55, 60]
])

Before we start accessing elements from this array, it’s important to understand its structure. Internally, bar is just a contiguous block of memory storing some data. Since we defined bar using a list of lists, NumPy makes it a two dimensional array, giving it two axes for indexing its values. Since this array has two axes, or dimensions, NumPy knows to interpret our data as a rectangular array where axis 0 is the row axis and axis 1 is the column axis. This means we can subset bar using a combination of row indices and column indices. Let’s see some examples using the 2d array we just created.

If you want to get the element at index (1,2), just use bar[1, 2].

bar[1, 2]
## 35

If you want to get the entire first row as a 1d array, use bar[0]. Remember, bar can be interpreted as an array of arrays, so the first element of bar is just a 1d array.

bar[0]
## array([ 5, 10, 15, 20])

If you want to get the entire first row as a 2d array, use the None keyword for the column index.

bar[0, None]
## array([[ 5, 10, 15, 20]])

We’ll learn more about the None keyword later. Alternatively, you can use slicing for the row index, like bar[:1].

bar[:1]
## array([[ 5, 10, 15, 20]])

If you’re feeling fancy, you can combine slicing, lists of indices, and negative indexing, like this.

bar[1:3, [-2, -1]]
## array([[35, 40],
##        [55, 60]])

And of course, you can make modifications. For example, we could replace the top left element of bar with -1 like this.

bar[0, 0] = -1
print(bar)
## [[-1 10 15 20]
##  [25 30 35 40]
##  [45 50 55 60]]

Or we could replace the second row with the third row like this.

bar[1] = bar[2]
print(bar)
## [[-1 10 15 20]
##  [45 50 55 60]
##  [45 50 55 60]]

Or we could insert zeros on diagonal like this.

bar[[0, 1, 2], [0, 1, 2]] = [0, 0, 0]
print(bar)
## [[ 0 10 15 20]
##  [45  0 55 60]
##  [45 50  0 60]]

Notice here that the ith row index and the ith column index combine together to select a specific array element. For example, row index 1 combines with column index 1 to select element (1,1) of bar, which we replace with the second 0.

Alright, so we’ve taken a hard look at indexing a two dimensional array. What about three and higher dimensional arrays? I suspect many people including my former self, interpret three dimensional arrays as rectangular prisms. The problem is that this spacial model breaks down when you go above three dimensions.

So, a better mental model in my opinion is, when you have a 1-dimensional array, think of a row of numbers. When you have a two dimensional array, think of a matrix - so, rows and columns. When you have a three dimensional array, instead of thinking of a rectangular prism, picture a row of matrices. Then when you get to four dimensions, you can imagine a matrix of matrices. It’s easy to see how you can expand this to any number of dimensions.

Now if you have a three dimensional array like this

zoo = np.array([
    [
        [10,20],
        [30,40],
        [50,60],
    ],
    [
        [11,12],
        [13,14],
        [15,16],
    ]
])

And you make an assignment like this

zoo[0,:,1] = 5

it’s easy to picture the result before you see it, because you can interpret this assignment as saying “set the 1st matrix, every row, 2nd column equal to 5”.

print(zoo)
## [[[10  5]
##   [30  5]
##   [50  5]]
## 
##  [[11 12]
##   [13 14]
##   [15 16]]]

So, everything we’ve looked at for indexing a two dimensional array can be carried over to a three or higher dimensional array.

Now, for the sake of full disclosure, I’m actually glossing over some gritty details and complex scenarios which I’ll cover later when we do advanced array indexing. And if you don’t finish this course, I highly recommend you read that section before you bow out. But at this point my goal is to cover the basics of array indexing so that we can start working with arrays in a meaningful way.


Course Curriculum

  1. Introduction
    1.1 Introduction
  2. Basic Array Stuff
    2.1 NumPy Array Motivation
    2.2 NumPy Array Basics
    2.3 Creating NumPy Arrays
    2.4 Indexing 1-D Arrays
    2.5 Indexing Multidimensional Arrays
    2.6 Basic Math On Arrays
    2.7 Challenge: High School Reunion
    2.8 Challenge: Gold Miner
    2.9 Challenge: Chic-fil-A
  3. Intermediate Array Stuff
    3.1 Broadcasting
    3.2 newaxis
    3.3 reshape()
    3.4 Boolean Indexing
    3.5 nan
    3.6 infinity
    3.7 random
    3.8 Challenge: Love Distance
    3.9 Challenge: Professor Prick
    3.10 Challenge: Psycho Parent
  4. Common Operations
    4.1 where()
    4.2 Math Functions
    4.3 all() and any()
    4.4 concatenate()
    4.5 Stacking
    4.6 Sorting
    4.7 unique()
    4.8 Challenge: Movie Ratings
    4.9 Challenge: Big Fish
    4.10 Challenge: Taco Truck
  5. Advanced Array Stuff
    5.1 Advanced Array Indexing
    5.2 View vs Copy
    5.3 Challenge: Population Verification
    5.4 Challenge: Prime Locations
    5.5 Challenge: The Game of Doors
    5.6 Challenge: Peanut Butter
  6. Final Boss
    6.1 as_strided()
    6.2 einsum()
    6.3 Challenge: One-Hot-Encoding
    6.4 Challenge: Cumulative Rainfall
    6.5 Challenge: Table Tennis
    6.6 Challenge: Where’s Waldo
    6.7 Challenge: Outer Product