Numpy Arrays and matrices

Shape of a Matrix

In [1]:
import numpy as np
x = np.array([4,3])
x
Out[1]:
array([4, 3])

Among the things that come to mind when I think of a matrix or its dimensions is accessing the dimensions of an NumPy array which is actually very straightforward. To do this, we'll use
x.shape.

In [2]:
x.shape
Out[2]:
(2,)

This brings up that it is a two element array.
Now if we had a multidimensional array for example:

  • I've now got a two by three NumPy array. And I can prove this by going into its shape, just as I did for our x array.
In [3]:
# let's define a 2 by 3 array
y = np.array([[1,2,3],[4,4,3]])
y
Out[3]:
array([[1, 2, 3],
       [4, 4, 3]])
In [4]:
#I can prove this by going into its shape,
y.shape
Out[4]:
(2, 3)

So shape is the way we typically access the dimensions of any NumPy array.


Transpose of a matrix

An additional manipulation to matrices that is often done in mathematics is the transpose operation whereby we take a matrix. And we switch its rows for columns and its columns for rows, fundamentally flipping the matrix.

  • For instance, if we went to our NumPy array y, you would be turning this from a 2 by 3 matrix to a 3 by 2 matrix where the rows and columns are flipped.
  • And this just as finding the shape of an array is very straightforward.
  • In NumPy, I need simply type in y.transpose.
In [5]:
y
Out[5]:
array([[1, 2, 3],
       [4, 4, 3]])
In [6]:
y.transpose()
Out[6]:
array([[1, 4],
       [2, 4],
       [3, 3]])

You see now that I have a 3 by 2 NumPy array. And if I'd like to check that, m can always set that equal to something and then have a look at its shape.

In [7]:
z = y.transpose()
z.shape
Out[7]:
(3, 2)

And indeed, we see that we have ourselves a 3 by 2 matrix.


Addition and subtraction of matrices

Addition and subtraction of matrices works just like we've come to it from math.

In [8]:
z
Out[8]:
array([[1, 4],
       [2, 4],
       [3, 3]])
In [9]:
y
Out[9]:
array([[1, 2, 3],
       [4, 4, 3]])

Two matrices may be added or subtracted only if they have the same dimension; that is, they must have the same number of rows and columns. Addition or subtraction is accomplished by adding or subtracting corresponding elements.


Matrix Multiplication

What's particularly interesting in the way NumPy handles multiplication. Now if we've got a matrix y and, say, I come up with a second array z, which is y plus three just to give ourselves a second array,

In [11]:
z = y + 3
z
Out[11]:
array([[4, 5, 6],
       [7, 7, 6]])

I can multiply these as follows, z times y. What this performs is elementwise multiplication. Traditionally, NumPy will perform elementwise multiplication.

In [12]:
z * y
Out[12]:
array([[ 4, 10, 18],
       [28, 28, 18]])

However, there will be times when one will want to perform traditional algebraic matrix multiplication.
For this, number has built in np.matmul.

Now let's recall that to be able to multiply two matrices,

  • The number of columns in the first matrix must be equal to the number of rows in the second matrix
  • if we're multiplying them in that order. If we satisfy this condition, we can place these two matrices into the NumPy.matmul method.

Now let's recall that originally, I had a NumPy array x, which was a 1 by 2 matrix. So I'm going to bring in z, which we know to have precisely this, two rows.

In [13]:
x
Out[13]:
array([4, 3])
In [14]:
z
Out[14]:
array([[4, 5, 6],
       [7, 7, 6]])

Now performing a matrix multiplication would be as simple as np.matmul(x,z) and out comes algebraic matrix multiplication. And as expected, if we're multiplying a 1 by 2 matrix by a 2 by 3 matrix, the results will have one row. And three columns and here we are.

In [15]:
np.matmul(x,z)
Out[15]:
array([37, 41, 42])

Definition


Shape = (1,3) . (3,1) = (1,)

$\begin{bmatrix}a & b & c \end{bmatrix} \begin{bmatrix}x \\ y \\ z\end{bmatrix} = \begin{bmatrix}a.x + b.y + c.z\end{bmatrix}$

Shape = (3,1) . (1,3) = (3,3)

$\begin{bmatrix}x \\ y \\ z\end{bmatrix}\begin{bmatrix}a & b & c\end{bmatrix}= \begin{bmatrix}x.a & x.b & x.c \\ y.a & y.b & y.c\\ z.a & z.b & z.c \end{bmatrix}$



More Generally Matrix of shape(x,y) $\times$ matrix of shape(y,z) will have a shape of (x,z)


Sine, Cosine, Tangent,Exponential, Logarithm

We've seen all throughout math, sine, cosine, tangent, exponention, you name it. They work wonderfully with NumPy arrays.


  • So let's go ahead to x, which I've already instantiated. And what I'm going to do is exponential create the elements in x elementwise.
  • What this will do is raise e to each of the elements and x. This is wonderfully convenient because we don't have to write any back end to do this elementwise NumPy takes care of it completely for us.
In [16]:
np.exp(x)
Out[16]:
array([54.59815003, 20.08553692])
In [17]:
np.log(np.exp(x))
Out[17]:
array([4., 3.])
In [18]:
np.cos(x)
Out[18]:
array([-0.65364362, -0.9899925 ])
In [19]:
np.sin(x)
Out[19]:
array([-0.7568025 ,  0.14112001])
In [20]:
np.tanh(x)
Out[20]:
array([0.9993293 , 0.99505475])

Example:

Write a function called operations that takes as input two positive integers h and w, makes two random matrices A and B, of size h x w, and returns A,B, and s, the sum of A and B.

In [21]:
def operations(h,w):
    """
    Takes two inputs, h and w, and makes two Numpy arrays A and B of size
    h x w, and returns A, B, and s, the sum of A and B.

    Arg:
      h - an integer describing the height of A and B
      w - an integer describing the width of A and B
    Returns (in this order):
      A - a randomly-generated h x w Numpy array.
      B - a randomly-generated h x w Numpy array.
      s - the sum of A and B.
    """
    A = np.random.random([h,w])
    B = np.random.random([h,w])
    s = A + B
    return A,B,s
In [24]:
A,B,s = operations(3,4)
In [26]:
assert(A.shape == B.shape == s.shape)