# Matrices

# Matrices¶

Matrices are used to represent data tables. You can think of the columns as different data features/characteristics and the rows as different entries. You can also use matrices together with vectors to represent linear systems of equations. So, let’s learn about them.

Let’s make a matrix to play with:

```
import numpy as np
np.random.seed(1234) # This is to ensure reproducibility
# of the random numbers
A = np.random.rand(4, 6)
A
```

```
array([[0.19151945, 0.62210877, 0.43772774, 0.78535858, 0.77997581,
0.27259261],
[0.27646426, 0.80187218, 0.95813935, 0.87593263, 0.35781727,
0.50099513],
[0.68346294, 0.71270203, 0.37025075, 0.56119619, 0.50308317,
0.01376845],
[0.77282662, 0.88264119, 0.36488598, 0.61539618, 0.07538124,
0.36882401]])
```

Notice that we used an list of rows and each row was a list of numbers.
Here are the dimensions of `A`

:

```
A.ndim
```

```
2
```

```
A.shape
```

```
(4, 6)
```

You see that `A.shape`

has two entries. The first is the number of matrix rows and the second is the number of matrix columns.

Let’s access some elements of `A`

:

```
A[0, 0]
```

```
0.1915194503788923
```

```
A[2, 2]
```

```
0.37025075479039493
```

You can access the 3rd row like this:

```
A[2]
```

```
array([0.68346294, 0.71270203, 0.37025075, 0.56119619, 0.50308317,
0.01376845])
```

Here is how you can get a the third column:

```
A[:, 2]
```

```
array([0.43772774, 0.95813935, 0.37025075, 0.36488598])
```

You can get a submatrix, say the first 3x3 submatrix like this:

```
A[:3, :3]
```

```
array([[0.19151945, 0.62210877, 0.43772774],
[0.27646426, 0.80187218, 0.95813935],
[0.68346294, 0.71270203, 0.37025075]])
```

And so on.

You can multiply matrices with numbers:

```
2.0 * A
```

```
array([[0.3830389 , 1.24421754, 0.87545548, 1.57071717, 1.55995162,
0.54518521],
[0.55292851, 1.60374436, 1.91627871, 1.75186527, 0.71563454,
1.00199025],
[1.36692587, 1.42540405, 0.74050151, 1.12239237, 1.00616633,
0.0275369 ],
[1.54565324, 1.76528238, 0.72977197, 1.23079236, 0.15076248,
0.73764801]])
```

```
A * 3.0
```

```
array([[0.57455835, 1.86632631, 1.31318322, 2.35607575, 2.33992742,
0.81777782],
[0.82939277, 2.40561653, 2.87441806, 2.6277979 , 1.07345181,
1.50298538],
[2.05038881, 2.13810608, 1.11075226, 1.68358856, 1.5092495 ,
0.04130535],
[2.31847986, 2.64792357, 1.09465795, 1.84618854, 0.22614372,
1.10647202]])
```

You can raise them to a power:

```
A ** 3
```

```
array([[7.02487596e-03, 2.40768115e-01, 8.38710745e-02, 4.84399833e-01,
4.74507846e-01, 2.02554647e-02],
[2.11308499e-02, 5.15603000e-01, 8.79601649e-01, 6.72066304e-01,
4.58124896e-02, 1.25747831e-01],
[3.19260289e-01, 3.62012846e-01, 5.07560548e-02, 1.76743777e-01,
1.27326662e-01, 2.61008780e-06],
[4.61579191e-01, 6.87626449e-01, 4.85815698e-02, 2.33058198e-01,
4.28341211e-04, 5.01715527e-02]])
```

You can pass them through functions:

```
np.exp(A)
```

```
array([[1.21108839, 1.86285223, 1.54918307, 2.19319324, 2.18141949,
1.31336508],
[1.31845982, 2.22971144, 2.60684155, 2.40111361, 1.43020426,
1.65036277],
[1.98072499, 2.03949459, 1.44809769, 1.75276788, 1.6538124 ,
1.01386367],
[2.16587973, 2.41727577, 1.44034978, 1.85038954, 1.07829516,
1.44603309]])
```

You can add them together:

```
A + A
```

```
array([[0.3830389 , 1.24421754, 0.87545548, 1.57071717, 1.55995162,
0.54518521],
[0.55292851, 1.60374436, 1.91627871, 1.75186527, 0.71563454,
1.00199025],
[1.36692587, 1.42540405, 0.74050151, 1.12239237, 1.00616633,
0.0275369 ],
[1.54565324, 1.76528238, 0.72977197, 1.23079236, 0.15076248,
0.73764801]])
```

You can multiply them together (assuming that the dimensions match):

```
B = np.random.randn(A.shape[1], 6)
B
```

```
array([[ 0.19342138, 0.55343891, 1.31815155, -0.46930528, 0.67555409,
-1.81702723],
[-0.18310854, 1.05896919, -0.39784023, 0.33743765, 1.04757857,
1.04593826],
[ 0.86371729, -0.12209157, 0.12471295, -0.32279481, 0.84167471,
2.39096052],
[ 0.07619959, -0.56644593, 0.03614194, -2.0749776 , 0.2477922 ,
-0.89715678],
[-0.13679483, 0.01828919, 0.75541398, 0.21526858, 0.84100879,
-1.44581008],
[-1.40197328, -0.1009182 , -0.54824245, -0.14461951, 0.35402033,
-0.03551303]])
```

```
C = A.dot(B)
C
```

```
array([[-0.12781667, 0.25323786, 0.52768426, -1.5223738 , 2.0965895 ,
-0.49268621],
[ 0.04962235, 0.34499945, 0.19218844, -1.98141413, 2.52857154,
1.3062625 ],
[ 0.27612724, 0.77770417, 1.05631158, -1.25793799, 2.08698996,
-0.84250615],
[-0.17747985, 0.93342159, 0.59003913, -1.49668376, 2.10029534,
-0.28282272]])
```

```
C.shape
```

```
(4, 6)
```

You can multiply a matrix with a vector:

```
a = np.random.randn(A.shape[1])
a
```

```
array([ 0.56573831, 1.5456588 , -0.97423633, -0.07034488, 0.30796886,
-0.20849876])
```

```
A.dot(a)
```

```
array([0.7715946 , 0.40649538, 1.24012955, 1.34902033])
```

You can also interchange the rows of a matrix with each columns. Let’s make a new matrix for this:

```
A.T
```

```
array([[0.19151945, 0.27646426, 0.68346294, 0.77282662],
[0.62210877, 0.80187218, 0.71270203, 0.88264119],
[0.43772774, 0.95813935, 0.37025075, 0.36488598],
[0.78535858, 0.87593263, 0.56119619, 0.61539618],
[0.77997581, 0.35781727, 0.50308317, 0.07538124],
[0.27259261, 0.50099513, 0.01376845, 0.36882401]])
```

```
A.T.shape
```

```
(6, 4)
```

There are some special numpy functions for creating arrays. Here is how to make an array of zeros:

```
np.zeros((4, 5))
```

```
array([[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.]])
```

An array of ones:

```
np.ones((5, 2))
```

```
array([[1., 1.],
[1., 1.],
[1., 1.],
[1., 1.],
[1., 1.]])
```

A unit matrix:

```
np.eye(5)
```

```
array([[1., 0., 0., 0., 0.],
[0., 1., 0., 0., 0.],
[0., 0., 1., 0., 0.],
[0., 0., 0., 1., 0.],
[0., 0., 0., 0., 1.]])
```

There are some useful functions that can be applied to matrices. For example, here is how you can sum all the elements of a matrix:

```
A.sum()
```

```
12.78492251426415
```

But what if you wanted to sum all the rows for each column? You can do it like this:

```
A.sum(axis=0)
```

```
array([1.92427326, 3.01932417, 2.13100383, 2.83788358, 1.71625749,
1.15618019])
```

Let’s convince ourselves that this works as expected by working say on the third column of A. Here is the code to get the third row:

```
A[:, 2]
```

```
array([0.43772774, 0.95813935, 0.37025075, 0.36488598])
```

Let’s sum it up:

```
A[:, 2].sum()
```

```
2.1310038313825865
```

Is this the same as the the third element of `A.sum(axis=0)`

?

Okay, so when we do `sum(axis=0)`

we are saying sum over the axis 0 of the matrix, which corresponds to the rows.
What if we wanted to sum over the columns.
We could do this:

```
A.sum(axis=1)
```

```
array([3.08928296, 3.77122082, 2.84446352, 3.07995522])
```

Verify this by hand as well. In the code-block below extract the 2nd row of the matrix and sum it up:

```
# your code here
```