Recall from yesterday:¶
- To work with matrices and vectors in Python: use
numpy - central data type provided by
numpy: the array- rectangular, fixed size
- same data type for all elements ($\neq$ lists!)
- use 1D arrays for vectors, 2D arrays for matrices
- create numpy arrays from:
- lists (
np.array([1, 2, 3])) linspace(plotting!)zeros,ones,full,eye
- lists (
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
a = np.array(["Hello "])
b = np.array(["world!"])
a + b # works in numpy>=2
array(['Hello world!'], dtype='<U12')
Showing more than one plot¶
Using matplotlib.pyplot, we can show many plots arranged in a grid using the command
subplot(RowsColumnsPlotnumber)
where the argument is given as three consecutive numbers, e.g. subplot(211) (2 rows, 1 column, plot nr 1).
Using 2 rows, 1 column¶
x = np.linspace(-2*np.pi, 2*np.pi, 100)
plt.figure(figsize=(8, 4)) # size in inches
plt.subplot(2, 1, 1)
plt.plot(x, np.sin(x), label="sin(x)")
plt.legend()
plt.subplot(2, 1, 2)
plt.plot(x, np.sin(2*x), label="sin(2*x)")
plt.legend();
Using 1 row, 2 columns¶
x = np.linspace(-2*np.pi, 2*np.pi, 100)
plt.figure(figsize=(12, 2))
plt.subplot(121) # equivalent to subplot(1, 2, 1)
plt.plot(x, np.sin(x), label="sin(x)");
plt.legend()
plt.subplot(122)
plt.plot(x, np.sin(2*x), label="sin(2*x)")
plt.legend();
Using 2 rows, 3 columns¶
x = np.linspace(-2*np.pi, 2*np.pi, 100)
plt.figure(figsize=(12, 4)) # width and height in inches
plt.subplot(231)
plt.plot(x, np.sin(x), label="sin(x)")
plt.ylabel("sin(x)")
plt.subplot(232)
plt.plot(x, np.sin(2*x), label="sin(2*x)")
plt.legend(loc='upper left')
plt.ylabel("sin(x)")
plt.subplot(233)
plt.plot(x, np.sin(3*x))
plt.subplot(234)
plt.plot(x, x)
plt.subplot(235)
plt.plot(x, x**2)
plt.subplot(236)
plt.plot(x, x**3)
plt.tight_layout()
More about numpy arrays¶
We can compare the built-in function range with the numpy functions linspace and arange.
range(start, stop, step) # only integers, stop not included
linspace(start, stop, number_of_numbers) # stop included (unless endpoint=False)
arange(start, stop, step) # stop not included
x1 = np.arange(0, 10, 2)
print(x1)
print(type(x1[0]))
x2 = np.arange(0, 10, 2, dtype=float)
print(x2)
print(type(x2[0]))
x3 = np.arange(0, 3, 0.5)
print(x3)
[0 2 4 6 8] <class 'numpy.int64'> [0. 2. 4. 6. 8.] <class 'numpy.float64'> [0. 0.5 1. 1.5 2. 2.5]
Solving systems of linear equations¶
If $A$ is a matrix and $b$ is a vector, you solve the linear system
$$A\cdot x = b$$
using np.linalg.solve, which has the syntax x = solve(A, b).
A = np.array([[1., 2.],
[3., 4.]])
b = np.array([1., 4.])
x = np.linalg.solve(A, b)
print(f"{x = }")
print(f"{A @ x = }") # should be almost b
x = array([ 2. , -0.5]) A @ x = array([1., 4.])
Slices for matrices¶
Slices are similar to that of lists and vectors except that there are now two dimensions.
M[i,:] a vector filled by the row $i$ of $M$.
M[:,j] a vector filled by the column $j$ of $M$.
M[2:4,:] slice 2:4 on the rows only
M[2:4,1:4]slice on rows and columns
Slices ‐ omitting a dimension¶
If you omit an index, NumPy assumes you are taking rows only.
M[3] is the third row of $M$
M[1:3] is a matrix with the second and third rows of $M$
Slices, examples¶
M = np.array([[1, 2, 3, 4 ],
[10, 20, 30, 40 ],
[100, 200, 300, 400]])
print(f"{M[2, :] = }") # row 2
print(f"{M[:, 2] = }") # column 2
print(f"{M[:, 1:3] = }") # slice on columns
print(f"{M[0:2] = }") # omitting a dimension
M[2, :] = array([100, 200, 300, 400])
M[:, 2] = array([ 3, 30, 300])
M[:, 1:3] = array([[ 2, 3],
[ 20, 30],
[200, 300]])
M[0:2] = array([[ 1, 2, 3, 4],
[10, 20, 30, 40]])
Some technical terms¶
There are three attributes ndim, shape and size that can be used on an array.
M = np.array([[1, 2, 3, 4 ],
[10, 20, 30, 40 ],
[100, 200, 300, 400]])
print(f"dimension: {M.ndim = }") # the dimension
print(f"shape: {M.shape = }") # M is a 3 times 4 matrix
print(f"size: {M.size = }") # the total number of elements
dimension: M.ndim = 2 shape: M.shape = (3, 4) size: M.size = 12
Dimensions of matrix slices¶
| access | ndim | kind | example |
|---|---|---|---|
| index, index | 0 | scalar | M[2, 0] |
| slice,index | 1 | vector | M[1, :] |
| slice, slice | 2 | matrix | M[0:2, 2:3] |
Example 1¶
Make a slice for the red elements. What is the dimension of the slice? $$ M = \begin{pmatrix} 0 & \color{red}{\begin{matrix} 1 & 2 & 3 \end{matrix}} \\ 4 & \color{red}{\begin{matrix} 5 & 6 & 7 \end{matrix}} \\ 8 & \begin{matrix} 9 & 10 & 11 \end{matrix} \end{pmatrix} $$
Example 2¶
Make a slice for the red elements. What is the dimension of the slice? $$ M = \begin{pmatrix} 0 & \begin{matrix} 1 & 2 \end{matrix} & 3 \\ 4 & \begin{matrix} 5 & 6 \end{matrix} & 7 \\ 8 & \color{red}{\begin{matrix} 9 & 10 \end{matrix}} & 11 \end{pmatrix} $$
5 min, let's go!
M = np.array([[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]])
print(f"{M[0:2, 1:].shape = }")
print(f"{M[0:2, 1:].ndim = }")
print(f"{M[-1, 1:-1].shape = }")
print(f"{M[-1, 1:-1].ndim = }")
M[0:2, 1:].shape = (2, 3) M[0:2, 1:].ndim = 2 M[-1, 1:-1].shape = (2,) M[-1, 1:-1].ndim = 1
Altering a matrix¶
You may alter a matrix using slices and direct access.
M[2, 3] = 2 # don't use M[2][3] = 2
M[2, :] = some_vector
M[1:3, :] = some_matrix
M[1:4; 2:5] = some_matrix
The matrices and vectors above must have the right size to "fit" in the matrix $M$.
Reshaping¶
From a given tensor (vector or matrix or higher dimension tensor) one may obtain a new tensor by reshaping.
A = np.arange(12)
print(A)
[ 0 1 2 3 4 5 6 7 8 9 10 11]
A1 = A.reshape((3, 4))
print(A1)
[[ 0 1 2 3] [ 4 5 6 7] [ 8 9 10 11]]
#A2 = A.reshape(2, 3) # error
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) Cell In[32], line 1 ----> 1 A2 = A.reshape(2, 3) # error ValueError: cannot reshape array of size 12 into shape (2,3)
Reshaping trick¶
Python can guess one of the dimensions. Give a negative index for the dimension to be guessed.
A = np.arange(12)
print(A)
[ 0 1 2 3 4 5 6 7 8 9 10 11]
A1 = A.reshape(4, -1)
print(A1)
[[ 0 1 2] [ 3 4 5] [ 6 7 8] [ 9 10 11]]
#A2 = A.reshape(5, -1) # error
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) Cell In[35], line 1 ----> 1 A2 = A.reshape(5, -1) # error ValueError: cannot reshape array of size 12 into shape (5,newaxis)
Changing the diagonal¶
For some applications it might be useful to change the diagonal only. This can be done with the numpy function diag_indices.
A = np.arange(16)
B = A.reshape(4, -1)
#print(B)
diagonal = np.diag_indices(B.shape[0])
#print(diagonal)
#print(type(diagonal))
# change the diagonal
B[diagonal] = 1.
print(B)
[[ 1 1 2 3] [ 4 1 6 7] [ 8 9 1 11] [12 13 14 1]]
Building matrices¶
hstackto stack matrices horizontallyvstackto stack matrices verticallycolumn_stackto stack vectors in columns
v0 = np.array([1, 2])
v1 = np.array([3, 4])
M0 = np.hstack([v0, v1]) # the argument is a list of vectors
M1 = np.vstack([v0, v1])
M2 = np.column_stack([v0, v1])
print(M0,'\n')
print(M1,'\n')
print(M2)
[1 2 3 4] [[1 2] [3 4]] [[1 3] [2 4]]
Methods sum(), max(), min()¶
A = np.arange(1, 9).reshape(2, -1)
print(f"{A = }")
print(f"{A.sum() = }")
print(f"{A.max() = }")
print(f"{A[0].max() = }")
A = array([[1, 2, 3, 4],
[5, 6, 7, 8]])
A.sum() = np.int64(36)
A.max() = np.int64(8)
A[0].max() = np.int64(4)
Boolean arrays¶
B1 = np.array([[True, False],
[False, True]])
print(f"{B1 = }")
B2 = np.full((3, 4), False)
print(f"{B2 = }")
B1 = array([[ True, False],
[False, True]])
B2 = array([[False, False, False, False],
[False, False, False, False],
[False, False, False, False]])
Using Boolean arrays¶
One may use Boolean arrays to create a "template" for modifying another array:
B = np.array([[True, False],
[False, True]]) # the template array
M = np.array([[2, 3],
[1, 4]]) # the other array
M[B] = 0 # using the template
print(M, "\n")
M[B] = 10, 20
print(M)
[[0 3] [1 0]] [[10 3] [ 1 20]]
Creating Boolean arrays¶
A comparison operator operating on an array, will create a Boolean array.
M = np.array([[2, 3],
[1, 4]])
B1 = M > 2
B2 = M == 4
print(B1,'\n')
print(B2)
[[False True] [False True]] [[False False] [False True]]
Creating and using Boolean arrays¶
M = np.array([[2, 3],
[1, 4]])
B1 = M > 2 # creating a template
M[B1] = 0 # using the template
print(M)
[[2 0] [1 0]]
We don't have to create a template variable:
M = np.array([[2, 3],
[1, 4]])
M[M>2] = 0 # creating a template and using it
print(M)
[[2 0] [1 0]]
Comparing arrays¶
M1 = np.array([[2, 3],
[1, 4]])
M2 = np.array([[0, 5],
[2, 3]])
B = M2 < M1
print(B,'\n')
C = M2 == M1
print(C)
[[ True False] [False True]] [[False False] [False False]]
Array equality¶
Because array comparisons create Boolean arrays, we need some method for checking equality. We can use the methods all or any.
A = np.array([[1,2],[3,4]])
B = np.array([[1,2],[3,3]])
print(f"{(A == B).all() = }")
print(f"{(A != B).any() = }")
(A == B).all() = np.False_ (A != B).any() = np.True_
Boolean operators for arrays¶
We cannot use and,or, not, for Boolean arrays. Instead we use following operators:
- and:
A & B - or:
A | B - not:
~A(the tilde symbol)
a = np.array([True, True, False, False])
b = np.array([True, False, True, False])
print(f"{a & b = }")
print(f"{a | b = }")
print(f"{~a = }")
a & b = array([ True, False, False, False]) a | b = array([ True, True, True, False]) ~a = array([False, False, True, True])
x = np.arange(0, 2*np.pi, np.pi/2)
y = np.sin(x) # the numpy function sin is a ufunc
print(x)
print(y)
[0. 1.57079633 3.14159265 4.71238898] [ 0.0000000e+00 1.0000000e+00 1.2246468e-16 -1.0000000e+00]
Vectorized functions¶
Non-universal functions can be wrapped to behave like universal functions. This is done by the command vectorize.
# A non-universal function
def const(x):
return 1
x = np.linspace(-1, 1, 100)
y1 = const(x)
print(f"{y1 = }")
vconst = np.vectorize(const)
y2 = vconst(x)
print(f"{type(y2) = }")
plt.plot(x, y2)
plt.xlabel("x")
plt.ylabel("y");
y1 = 1 type(y2) = <class 'numpy.ndarray'>
Another vectorised example¶
# A non-universal function
@np.vectorize
def heaviside(x): # named after Oliver Heaviside
if x >= 0:
return 1
else:
return 0
x = np.linspace(-1, 1, 200)
plt.plot(x, heaviside(x));
Images as matrices¶
For demonstration purposes, we can use an image of a racoon provided by scipy.
import scipy
M = scipy.datasets.face(gray=True) # for starters, use a gray scale
print("M:", type(M))
print("M.shape =", M.shape)
print("dtype =", M.dtype)
plt.imshow(M, cmap='gray'); # use a gray scale color map (cmap)
M: <class 'numpy.ndarray'> M.shape = (768, 1024) dtype = uint8
Arithmetic operations¶
M = scipy.datasets.face(gray = True)
M1 = 255 - M # negative image
M2 = ((M / 255)**2) * 255 # quadratic function
plt.figure(figsize=(12, 4)) # 12" wide and 4" high
plt.subplot(131)
plt.imshow(M, cmap='gray')
plt.subplot(132)
plt.imshow(M1, cmap='gray')
plt.subplot(133)
plt.imshow(M2, cmap='gray', vmin = 0, vmax = 255);
Slices¶
M = scipy.datasets.face(gray = True)
M1 = M[400:600, :]
M2 = M[:600, 600:]
plt.figure(figsize=(12, 4))
plt.subplot(131)
plt.imshow(M, cmap='gray')
plt.subplot(132)
plt.imshow(M1, cmap='gray')
plt.subplot(133)
plt.imshow(M2, cmap='gray');
Boolean arrays¶
plt.figure(figsize=(12, 4))
M = scipy.datasets.face(gray = True)
plt.subplot(131)
plt.imshow(M, cmap='gray')
B = M > 127
M[B] = 255
plt.subplot(132)
plt.imshow(M, cmap='gray')
M[M <= 127] = 0
plt.subplot(133)
plt.imshow(M, cmap='gray');
RGB images¶
M = scipy.datasets.face()
print("M.shape =", M.shape)
print("M.ndim =", M.ndim)
print("dtype =", M.dtype)
print("M[0, 0] =", M[0, 0])
plt.imshow(M)
M.shape = (768, 1024, 3) M.ndim = 3 dtype = uint8 M[0, 0] = [121 112 131]
<matplotlib.image.AxesImage at 0x108178a70>
Slices¶
M = scipy.datasets.face().copy()
plt.figure(figsize=(12, 4))
plt.subplot(131)
plt.imshow(M)
M[:, :, 0] = 255 # maximize red for each pixels
plt.subplot(132)
plt.imshow(M)
# R G B
M[100:200, 100:800] = [0, 0, 255] # make a blue rectangle
plt.subplot(133)
plt.imshow(M);
Comparison and Boolean operators¶
M = scipy.datasets.face().copy()
plt.figure(figsize=(8, 4))
plt.subplot(121)
plt.imshow(M)
# [ R, G, B]
g_larger_than_r = M[:, :, 1] > M[:, :, 0]
g_larger_than_b = M[:, :, 1] > M[:, :, 2]
g_larger_than_both = g_larger_than_r & g_larger_than_b
print(g_larger_than_both.shape)
M[g_larger_than_both, 1] = 0 # remove green from mostly green pixels
plt.subplot(122)
plt.imshow(M);
(768, 1024)
Other images¶
Use Python Image Library, PIL.
from PIL import Image
img = Image.open("hike.jpg")
img_array = np.array(img)
print(img_array.shape)
plt.imshow(img_array);
(203, 271, 3)