Week 1 (1/31-2/6)

Notebook

Weekly digest

Logistics

  • Syllabus and course organization

Numpy

  • Numpy arrays

  • Vectorization

  • Indexing and slicing

  • Aggregating and sorting

  • Broadcasting

Resources

1. Visualizing numpy arrays

[1]:
import matplotlib.pyplot as plt
import numpy as np

def show(a, size=6, cmap="seismic", text='limegreen', fontsize="large"):
    '''
    Display an image of a 2-dimensional numpy array.
    It is assumed that values of the array are between
    0 and 1.
    '''

    h, w = a.shape
    plt.figure(figsize=(size, size))
    ax = plt.subplot(111)
    plt.xticks(range(w + 1))
    plt.yticks(range(h + 1))
    for (j, i), v in np.ndenumerate(a):
        ax.text(i,
                j,
                f"{v:.1f}",
                ha='center',
                va='center',
                color=text,
                weight=900,
                fontsize=fontsize)
    plt.imshow(a, cmap=cmap, vmin=0, vmax=1)
    plt.show()

Exercises

The exercise below should be completed using tools provided by numpy arrays. Do not use for or while loops, list comprehensions etc. The code in each case can be written in fewer than 10 lines.

Exercise 1

Write a function border(a) which takes as an argument an 2-dimensional numpy array a and returns an array obtained by adding a border of zeros to a.

[3]:
a = np.arange(12).reshape(3, 4)
print(f"a:\n{a}\n")
print(f"border(a):\n{border(a)}")
a:
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]

border(a):
[[ 0  0  0  0  0  0]
 [ 0  0  1  2  3  0]
 [ 0  4  5  6  7  0]
 [ 0  8  9 10 11  0]
 [ 0  0  0  0  0  0]]

Exercise 2

Write a function row_split(a, k) which for a given 2-dimensional numpy array a and a positive integer k returns a tuple of two 2-dimensional numpy arrays: one consisting of the first k rows of a and the second consisting of the remaining rows.

[5]:
a = np.arange(15).reshape(5, 3)
splitted = row_split(a, 3)
print(f"a:\n{a}")
print(f"\nrow_split(a, 3):\n{splitted[0]}\n\n {splitted[1]}")
a:
[[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]
 [12 13 14]]

row_split(a, 3):
[[0 1 2]
 [3 4 5]
 [6 7 8]]

 [[ 9 10 11]
 [12 13 14]]

Exercise 3

Write a function n_smallest(a, n) which given a 1-dimensional numpy array a and an integer n returns an array with indices of n smallest elements of a.

[9]:
rng = np.random.default_rng(0) # initialize the random number generator
a = rng.integers(0, 100, 10) # array of random integers
print(f"a:\n{a}\n")
print(f"n_smallest(a, 3):\n{n_smallest(a, 3)}")
a:
[85 63 51 26 30  4  7  1 17 81]

n_smallest(a, 3):
[7 5 6]

Exercise 4

Write function checkers(n) which returns an \(n\times n\) numpy array consisting of zeros and ones arranged in a checkerboard pattern. To check that this function works correctly, test it for both odd and even values of \(n\).

[11]:
checkers(8)
[11]:
array([[1., 0., 1., 0., 1., 0., 1., 0.],
       [0., 1., 0., 1., 0., 1., 0., 1.],
       [1., 0., 1., 0., 1., 0., 1., 0.],
       [0., 1., 0., 1., 0., 1., 0., 1.],
       [1., 0., 1., 0., 1., 0., 1., 0.],
       [0., 1., 0., 1., 0., 1., 0., 1.],
       [1., 0., 1., 0., 1., 0., 1., 0.],
       [0., 1., 0., 1., 0., 1., 0., 1.]])

Exercise 5

Write a function sub_table(n) which returns an \(n\times n\) numpy array with the subtraction table of numbers from \(0\) to \(n-1\). The value in the row \(i\) and column \(j\) of the array should be the number \(i - j\).

[13]:
sub_table(11)
[13]:
array([[  0,  -1,  -2,  -3,  -4,  -5,  -6,  -7,  -8,  -9, -10],
       [  1,   0,  -1,  -2,  -3,  -4,  -5,  -6,  -7,  -8,  -9],
       [  2,   1,   0,  -1,  -2,  -3,  -4,  -5,  -6,  -7,  -8],
       [  3,   2,   1,   0,  -1,  -2,  -3,  -4,  -5,  -6,  -7],
       [  4,   3,   2,   1,   0,  -1,  -2,  -3,  -4,  -5,  -6],
       [  5,   4,   3,   2,   1,   0,  -1,  -2,  -3,  -4,  -5],
       [  6,   5,   4,   3,   2,   1,   0,  -1,  -2,  -3,  -4],
       [  7,   6,   5,   4,   3,   2,   1,   0,  -1,  -2,  -3],
       [  8,   7,   6,   5,   4,   3,   2,   1,   0,  -1,  -2],
       [  9,   8,   7,   6,   5,   4,   3,   2,   1,   0,  -1],
       [ 10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0]])

Exercise 6

If \({\bf v} = [x_1, x_2, \dots, x_n]\) and \({\bf w} = [y_1, y_2, \dots, y_n]\) are two vectors with \(n\) coordinates then the Euclidean distance between \(\bf v\) and \(\bf w\) is given by the formula:

\[d({\bf v}, {\bf w}) = \sqrt{ (x_1 - y_1)^2 + (x_2 - y_2)^2 + \dots + (x_n - y_n)^2}\]

Let X be an \(m\times n\) numpy array, and let w be a 1-dimensional array with \(n\) entries. Write a function dist(X, w) which returns a 1-dimensional array with \(m\) entries, such that the \(i\)-th entry is the distance between the \(i\)-th row of X and w.

[15]:
X = np.arange(12).reshape(3, 4)
w = np.array([0, 1, 0, 1])
print(f"X:\n{X}")
print(f"\nw:\n{w}")
print(f"\ndist(X, w):\n{dist(X,w)}")
X:
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]

w:
[0 1 0 1]

dist(X, w):
[ 2.82842712 10.19803903 18.11077028]

Exercise 7

Write a function order_columns(a) which takes as an argument a 2-dimensional numpy array and returns an array obtained by reordering columns of a according to the sum of their entries: the first column is the one where the sum of entries is the smallest, the last column is the one where the sum of entries is the largest.

[20]:
rng = np.random.default_rng(1) # initialize the random number generator
a = rng.integers(0, 6, (3,5)) # 3x5 array of random integers 0 <= n < 6
print(f"\na:\n{a}")
print(f"\norder_columns(a):\n{reorder_columns(a)}")

a:
[[2 3 4 5 0]
 [0 4 5 1 1]
 [5 2 1 4 1]]

order_columns(a):
[[0 2 3 4 5]
 [1 0 4 5 1]
 [1 5 2 1 4]]

Exercise 8

Write the function first_smaller(a, n) which takes as its argument a 1-dimensional numpy array a and a number n and returns the first entry of a which is smaller than n. If such entry does not exist the function should return None.

[26]:
rng = np.random.default_rng(0) # initialize the random number generator
a = rng.integers(0, 100, 10) # array of 10 random integers 0 <= n < 100
print(f"\na:\n{a}")
print(f"\nfirst_smaller(a, 50):\n{first_smaller(a, 50)}")

a:
[85 63 51 26 30  4  7  1 17 81]

first_smaller(a, 50):
26