Performant Python

Copy and Access Numpy Arrays

Overview:

  • Teaching: 5 min
  • Exercises: 15 min

Questions

  • How do I copy numpy arrays?
  • How do I access elements or subsets of arrays?

Objectives

  • Understand the difference between assigining and copying numpy arrays.
  • Know how to access elements, slices and subsets of numpy arrays.

To Copy or not to Copy (Numpy Arrays)

First as always we must import numpy:

In [1]:
import numpy as np
In [2]:
a = np.array( [-1, 0, 1] )
print(a)
[-1  0  1]

Mow let's assign the array we've created to another variable:

In [3]:
b = a
print("a", a)
print("b", b)
a [-1  0  1]
b [-1  0  1]

If we now modify a what will happen to b

In [4]:
a[0]=2
print(a)
print(b)
[2 0 1]
[2 0 1]

When we assign b to a both variables point to the same object, (the same happens with lists!).

Copy()

If we want to copy a numpy array we must explicitly call <ndarray>.copy():

In [5]:
c = np.ones( (3,3) )
d = c
e = c.copy()
print("c", c)
print("d", d)
print("e", e)
c [[1. 1. 1.]
 [1. 1. 1.]
 [1. 1. 1.]]
d [[1. 1. 1.]
 [1. 1. 1.]
 [1. 1. 1.]]
e [[1. 1. 1.]
 [1. 1. 1.]
 [1. 1. 1.]]

Now let's modify c:

In [6]:
c[0][0]=10
print("c", c)
print("d", d)
print("e", e)
c [[10.  1.  1.]
 [ 1.  1.  1.]
 [ 1.  1.  1.]]
d [[10.  1.  1.]
 [ 1.  1.  1.]
 [ 1.  1.  1.]]
e [[1. 1. 1.]
 [1. 1. 1.]
 [1. 1. 1.]]

Re-initialise

What happens if we re-initialise c e.g.

c= np.zeroes( (3,3) )

Solution

Accessing arrays

Basic indexing and slicing can be used to access array elements, as we know from lists:

In [9]:
# a[start:stop:stride] (not inclusive of stop)
x = np.arange(8)
print("x", x)
print("x[0:7:2]", x[0:7:2])
print("x[0::2]", x[0::2])
x [0 1 2 3 4 5 6 7]
x[0:7:2] [0 2 4 6]
x[0::2] [0 2 4 6]

And as with lists negative indices are valid! Useful if you want to access from the end of the array

In [10]:
print(x[-1], x[-2], x[-3])
7 6 5

Access

What will the following do:

print(x[2:-3:2])
print(x[::-2])

Solution

Accessing Multidimensional data

To access multidimensional arrays we can use multiple index subscripts, or we can use a tuple.

In [12]:
# Basic indexing of a 3d array
m = np.array([[[1,2],[3,4]],[[5,6],[7,8]]])
print(c.shape)
# using subscripts
print("m[1][0][1]:", m[1][0][1])
# using a tuple
print("m[(1,0,1)]:", m[(1,0,1)])
# the whole thing
print(m)
(3, 3)
m[1][0][1]: 6
m[(1,0,1)]: 6
[[[1 2]
  [3 4]]

 [[5 6]
  [7 8]]]

We can access complete slices by leaving out indices or using elipses:

In [13]:
print(m[1])
print(m[1,0,...])     # can also use elipsis (3 dots)
                      # for missing indices   
print(m[...,1,1])     # anywhere in indices
print(m[...,...,1])   # but only once
[[5 6]
 [7 8]]
[5 6]
[4 8]
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-13-43f04eec0494> in <module>()
      3                       # for missing indices
      4 print(m[...,1,1])     # anywhere in indices
----> 5 print(m[...,...,1])   # but only once

IndexError: an index can only have a single ellipsis ('...')

Slice and Copy

Create a new array and assign a slice of the array to another variable.

What happens when you change an element of the original array that is in the slice you have created, or vice-versa?

How can you create a unique slice of the original array?

Solution

Key Points:

  • If you assign one array to another the two arrays are views of the same object.
  • If you want to copy an array, element or slice you need to explicitly copy the array.
  • Indexing and slicing works as with lists, you can use indexing or tuples to access elements
  • For slicing you can use a [start:stop:stride] notation to select from an array