Closure#
Syllabus Week 12: Numpy and matplotlib#
NumPy, a library for numeric computing in Python, especially when handling large arrays and matrices. Via examples, we will cover:
NumPy array, an n-dimensional array
Compact syntax
Vectorized NumPy operators, for example
+
,*
NumPy functions for element-wise operations:
numpy.sqrt()
,numpy.exp()
,numpy.sin()
,numpy.abs()
Other functions and methods:
numpy.mean()
,numpy.std()
Indexing, slicing, and boolean indexing
NumPy arrays are mutable
Preallocation
Matplotlib, a library for scientific visualization in Python. Via examples, we will cover:
Line plots
Bar plots
Labels
Legends
Titles
Text
Advanced#
Note about the material in Advanced section. The advanced material contains more some additional topics related to the weeks’s content. You are not required to read this material, and none of the exercises or exam questions will rely on this material.
Advanced 12.1: Linear Algebra with NumPy#
We can use NumPy for linear algebra. In NumPy, 2D arrays are interpreted as matrices, and 1D array and vectors. In Mathematics 1, you have used SymPy, but you can also use Numpy for calculations.
Check the code below for matrix-vector multiplication.
A = np.array([[4, 2, 2], [1, 5, 3], [2, 3, 3]])
x = np.array([0, 1, 2])
b = A @ x
print('A matrix, A = \n', A,'\n')
print('A vector, x =', x)
print('The matrix vector product Ax = b =', b)
You might think that both x
and b
look like row vectors and you might wonder why is it possible to calculate \(Ax\). In fact you can also compute \(xA\) with b = x @ A
, which would make sense if \(x\) was a row vector. The reason is that Python interprets x
as either a row or a column vector in order for the matrix multiplication to have the right dimensions.
You can also solve linear systems and perform eigen decomposition in NumPy. Below compute \(y\) for the linear system \(Ay = c\) and we also compute the eigenvalues and eigenvectors of \(A\).
A = np.array([[4, 1, 2], [1, 5, 3], [2, 3, 3]])
c = np.array([-1, 0, -1])
y = np.linalg.solve(A, c)
print('Solving Ay = c with \nA=\n', A, '\nand\nc=',c,',\ngives\ny=', y)
eigenvalues, eigenvectors = np.linalg.eig(A)
print('\n\n\nThe eigenvalues of A are: ', eigenvalues, '\n')
print('The eigenvectors of A are: \n', eigenvectors)
In the eigenvector matrix, each column is an eigenvector.
You can find a lot more Linear Algebra functions in Numpy here, https://www.w3schools.com/python/numpy/numpy_intro.asp, or ask Google or Chat-GPT.
Advanced 12.2: Heatmaps in Matplotlib#
With Matplotlib, you can plot a matrix by creating a an image (a heatmap) with plt.imshow()
. Say we wish to visualize the function \(f(x,y) = -(x-1)^2/2 - y^2\) in the region \([-2,2]\times [-2,2]\). Here is how you can do it
x = np.linspace(-2, 2, num=100)
y = np.linspace(-2, 2, num=100)
X, Y = np.meshgrid(x, y)
plt.imshow(-(X - 1)**2 / 2 - Y**2, extent=(-2, 2, -2, 2))
plt.colorbar()
plt.show()
Try to print X
and Y
to see what the mysterious functions np.meshgrid
does. Think about why it’s necessary to use it here.
Advanced 12.3: Why Preallocation Matters?#
Say you want to find the first 10 Fibbonacci numbers. The first two are given by
\(x_0 = 0\), and \(x_1 = 1\).
The next can be calculated by
\(x_2 = x_0 + x_1 = 1\),
\(x_3 = x_1 + x_2 = 2\),
and so on …
Let’s compute the first 10 Fibonacci numbers without preallocation using lists.
# Without preallocation using lists
N = 10
fib_numbers = [0,1]
for i in range(2,N):
fib_numbers.append(fib_numbers[i-2] + fib_numbers[i-1])
print('First 10 Fibbonacci numbers', fib_numbers)
Now without preallocation using NumPy arrays.
# Without preallocation using Numpy arrays
fib_numbers = np.array([0,1])
for i in range(2,N):
fib_numbers = np.append(fib_numbers,[fib_numbers[i-2] + fib_numbers[i-1]])
print('First 10 Fibbonacci numbers', fib_numbers)
And finally with preallocation using NumPy arrays.
# With preallocation using numpy arrays.
fib_numbers = np.empty(N, dtype=np.int64)
fib_numbers[0] = 0
fib_numbers[1] = 1
for i in range(2,N):
fib_numbers[i] = (fib_numbers[i-2] + fib_numbers[i-1])
print('First 10 Fibbonacci numbers', fib_numbers)
Try to see what happens when you increase N
to 100
, 1000
, 10000
, … Can you reach a point where the two top code blocks are slower? Tip: comment out the print statement!
Advanced 12.4: Counting Integers#
In Numpy there exists a ton of different functions for Numpy arrays, including one that does almost the same as array_frequencies()
that you created in the counting integers.
Run the line unique_values, counts = np.unique(array, return_counts=True)
where array
is an integer array, and check the output!