I am a data scientist working on time series forecasting (using R and Python 3) at the London Ambulance Service NHS Trust. I earned my PhD in cognitive neuroscience at the University of Glasgow working with fmri data and neural networks. I favour linux machines, and working in the terminal with Vim as my editor of choice.
First off, we need a class 'Mat' (as in 'matrix'). Matrix like data will be passed to the Mat class in the form of a list of lists, with each sub-list acting as a row. We will gradually build up a suit of methods to do all the needed operations.
Here is a function to print a matrix, one row beneath the other. This is helpful for debugging. We also include an option to round the values to a specified precision, which is useful to ignore very tiny rounding errors on what would otherwise be integer numbers:
We make a method to generate a matrix of a given size, populated with a particular set of values (default all zeros) and of a particular type (full by default, or optionally diagonal, upper, lower):
First, we ensure that we won't run out of values when populating the matrix. If a single value is passed, then we repeat that value. If more than one value is passed, but is less than the largest row/column dimension of the matrix, then we pad the value list with zeros. This scheme will allow us to make some quite useful types of matrices such as tri-diagonal etc.
Now that we have our list of values, we loop over each row/column of the matrix and decide whether to put a value from the list or a zero (in the case of diagonal/upper/lower matrices, we know some parts of the matrix will be zero).
If the matrix is to have a single diagonal, we place a value from the list once per row, in the jth column.
An interesting case is when we provide more than one value with family='full'. In this case we check which diagonal we're on (i.e. main, 1st off-diagonal, 2nd off-diagonal etc.) and pull the corresponding item (0th, 1st, 2nd) from the value list. If the original value list contained more than one value it will have been padded with zeros, and the result will be a matrix with some recurring number along each diagonal (see demos below). If only a single value was supplied then this value will have been repeated and the result will be a uniformly populated matrix
A useful matrix to generate immediately is the identity matrix. We use the previous function and populate the diagonal with 1's.
Outputs:
The Vandamonde matrix stores the components of an nth degree polynomial curve. It has as many rows as points on the curve and one column per term of the polynomial - the 1st column is all ones, and is the basis for the intercept ($x^0 = 1$); The second incrementally increases and forms the basis for the slope ($x^1 = x$); The third column is for the squared terms ($x^2 = x^2$) and so on. When a vector $b$ is [projected onto](../projection_and_regression.md) the column space of this matrix, the resulting projection is the 'best fitting' polynomial curve through the points $b$:
We generate a vandermonde matrix with terms up to cubic and print the result:
Outputs:
The size of a matrix is simply its number of rows and columns.
Here we return the number of rows, or columns, or both depending on the axis argument:
To transpose a matrix, we need a new matrix in which the rows are the former columns and the columns are the former rows:
We loop over the rows and columns of the input matrix, keeping a record of the row and column subscript indices. The transposed matrix is built up gradually with a set of new rows (each row being the values found in the corresponding column):
We create a matrix, call the transpose method and print the result:
Outputs:
While coding other functions in this library, I noticed I was often extracting a single row, column, or particular value from the matrix by doing:
This seemed a bit clunky so I defined a method with a more readable interface to do it:
We check to see if a row index 'i' and if a column index 'j' were passed. If only a row index was passed, we return that entire row. If only a column index was passed, we return the entire column (by transposing the matrix to make indexing a column easy) and if both were passed we return the value in the 'ith' and 'jth' column (as an integer):
In case we end up with a 1x1 matrix, we probably want to use it as a scalar (that's all a 1x1 matrix is...) and so we make a method that indexes the element for us (since the intent is more understandable than indexing directly):
This function works along the diagonal of the matrix, starting in the top left and stopping after running out of rows or columns.
We index the entire 2nd row, the entire 3rd column, or the value in row 2 column 3:
Outputs:
back to project main page
back to home