In [43]:
import numpy as np

Matrices and Vectors


In [44]:
A = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]])
A


Out[44]:
array([[ 1,  2,  3],
       [ 4,  5,  6],
       [ 7,  8,  9],
       [10, 11, 12]])

In [45]:
# initialise a vector
v = np.array([1,2,3])
v


Out[45]:
array([1, 2, 3])

In [46]:
# Get the dimension of the matrix A where m = rows and n = columns
[m, n] = A.shape
print(m, n)


4 3

In [47]:
# Get the dimension of the vector v 
dim_v = v.shape
dim_v


Out[47]:
(3,)

In [48]:
# Now let's index into the 2nd row 3rd column of matrix A
# Python arrays are zero indexed
A_23 = A[1,2]
A_23


Out[48]:
6

Addition and Scalar Multiplication


In [49]:
# Initialize matrix A and B 
A = np.array([[1, 2, 4], [ 5, 3, 2]])
B = np.array([[1, 3, 4], [1, 1, 1]])
print(A)
print(B)


[[1 2 4]
 [5 3 2]]
[[1 3 4]
 [1 1 1]]

In [50]:
# Initialize constant s 
s = 2

In [51]:
# See how element-wise addition works
add_AB = A + B
add_AB


Out[51]:
array([[2, 5, 8],
       [6, 4, 3]])

In [52]:
# See how element-wise subtraction works
sub_AB = A - B
sub_AB


Out[52]:
array([[ 0, -1,  0],
       [ 4,  2,  1]])

In [53]:
# See how scalar multiplication works
mult_As = A * s
mult_As


Out[53]:
array([[ 2,  4,  8],
       [10,  6,  4]])

In [54]:
# Divide A by s
div_As = A / s
div_As


Out[54]:
array([[ 0.5,  1. ,  2. ],
       [ 2.5,  1.5,  1. ]])

In [55]:
# What happens if we have a Matrix + scalar?
add_As = A + s
add_As


Out[55]:
array([[3, 4, 6],
       [7, 5, 4]])

Matrix Vector Multiplication


In [56]:
# Initialize matrix A 
A = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
A


Out[56]:
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

In [57]:
# Initialize vector v 
v = np.array([[1], [1], [1]])
v


Out[57]:
array([[1],
       [1],
       [1]])

In [58]:
# Multiply A * v
Av = np.dot(A, v)
Av


Out[58]:
array([[ 6],
       [15],
       [24]])

Matrix Matrix Multiplication


In [59]:
# Initialize a 3 by 2 matrix 
A = np.array([[1, 2], [3, 4], [5, 6]])
A


Out[59]:
array([[1, 2],
       [3, 4],
       [5, 6]])

In [60]:
# Initialize a 2 by 1 matrix 
B = np.array([[1], [2]])
B


Out[60]:
array([[1],
       [2]])

In [61]:
# We expect a resulting matrix of (3 by 2)*(2 by 1) = (3 by 1) 
mult_AB = np.dot(A, B)
mult_AB


Out[61]:
array([[ 5],
       [11],
       [17]])

Matrix Multiplication Properties


In [62]:
# Initialize random matrices A and B 
A = np.array([[1,2],[4,5]])
B = np.array([[1,1],[0,2]])
print(A)
print(B)


[[1 2]
 [4 5]]
[[1 1]
 [0 2]]

In [63]:
# Initialize a 2 by 2 identity matrix
I = np.identity(2)
I
# The above notation is the same as I = [1,0;0,1]


Out[63]:
array([[ 1.,  0.],
       [ 0.,  1.]])

In [64]:
# What happens when we multiply I*A ? 
IA = np.dot(I, A)
IA


Out[64]:
array([[ 1.,  2.],
       [ 4.,  5.]])

In [65]:
# How about A*I ? 
AI = np.dot(A, I)
AI


Out[65]:
array([[ 1.,  2.],
       [ 4.,  5.]])

In [66]:
# Compute A*B 
AB = np.dot(A, B)
AB


Out[66]:
array([[ 1,  5],
       [ 4, 14]])

In [67]:
# Is it equal to B*A? 
BA = np.dot(B, A)
BA


Out[67]:
array([[ 5,  7],
       [ 8, 10]])

In [68]:
# Note that IA = AI but AB != BA

Inverse and Transpose


In [69]:
# Initialize matrix A 
A = np.array([[1,2,0], [0,5,6], [7,0,9]])
A


Out[69]:
array([[1, 2, 0],
       [0, 5, 6],
       [7, 0, 9]])

In [70]:
# Transpose A 
A_trans = A.T
A_trans


Out[70]:
array([[1, 0, 7],
       [2, 5, 0],
       [0, 6, 9]])

In [71]:
# Take the inverse of A 
A_inv = np.linalg.inv(A)
A_inv


Out[71]:
array([[ 0.34883721, -0.13953488,  0.09302326],
       [ 0.3255814 ,  0.06976744, -0.04651163],
       [-0.27131783,  0.10852713,  0.03875969]])

In [72]:
# What is A^(-1)*A? 
A = np.array([[1,2,0], [0,5,6], [7,0,9]])
A_inv = np.linalg.inv(A)

A_invA = np.dot(np.linalg.inv(A), A)
A_invA
# Other are close to zero so effectively the identity matrix


Out[72]:
array([[  1.00000000e+00,  -8.32667268e-17,   5.55111512e-17],
       [ -2.77555756e-17,   1.00000000e+00,  -2.77555756e-17],
       [ -3.46944695e-17,   2.77555756e-17,   1.00000000e+00]])