# Source code for noize.mathfun.matrixfun

```#!/bin/bash
# Copyright 2019 Peggy Sylopp und Aislyn Rose GbR
# This file is part of the  NoIze-framework
# The NoIze-framework is free software: you can redistribute it and/or modify
# Free Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
#@author Aislyn Rose
#@version 0.1
#@date 31.08.2019
#
# The  NoIze-framework  is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU AFFERO General Public License
# along with the NoIze-framework. If not, see http://www.gnu.org/licenses/.

'''The matrixfun module offers insight into the matrix manipulation
necessary in both digital signal processing and machine learning
'''
import numpy as np

# TODO: https://github.com/biopython/biopython/issues/1496
# Fix numpy array repr for Doctest.
'''Adds tensor / dimension to input ndarray.

Keras requires an extra dimension at some layers, which represents
the 'tensor' encapsulating the data.

Further clarification taking the example below. The input matrix has
shape (2,3,4). Think of it as 2 different events, each having
3 sets of measurements, with each of those having 4 features. So,
let's measure differences between 2 cities at 3 different times of
day. Let's take measurements at 08:00, 14:00, and 19:00 in...
Magic City and Never-ever Town. We'll measure.. 1) tempurature,
2) wind speed 3) light level 4) noise level.

How I best understand it, putting our measurements into a matrix
with an added dimension/tensor, this highlights the separate
measurements, telling the algorithm: yes, these are 4 features
from the same city, BUT they occur at different times. Or it's
just how Keras set up the code :P

Parameters
----------
matrix : numpy.ndarray
The `matrix` holds the numerical data to add a dimension to.

Returns
-------
matrix : numpy.ndarray
The `matrix` with an additional dimension.

Examples
--------
>>> import numpy as np
>>> matrix = np.arange(24).reshape((2,3,4))
>>> matrix.shape
(2, 3, 4)
>>> matrix
array([[[ 0,  1,  2,  3],
[ 4,  5,  6,  7],
[ 8,  9, 10, 11]],
<BLANKLINE>
[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]])
>>> matrix_2.shape
(2, 3, 4, 1)
>>> matrix_2
array([[[[ 0],
[ 1],
[ 2],
[ 3]],
<BLANKLINE>
[[ 4],
[ 5],
[ 6],
[ 7]],
<BLANKLINE>
[[ 8],
[ 9],
,
]],
<BLANKLINE>
<BLANKLINE>
[[,
,
,
],
<BLANKLINE>
[,
,
,
],
<BLANKLINE>
[,
,
,
]]])
'''
if isinstance(matrix, np.ndarray) and len(matrix) > 0:
matrix = matrix.reshape(matrix.shape + (1,))
return matrix
elif isinstance(matrix, np.ndarray):
raise ValueError('Input matrix is empty.')
else:
raise TypeError('Expected type numpy.ndarray, recieved {}'.format(
type(matrix)))

[docs]def create_empty_matrix(shape, complex_vals=False):
'''Allows creation of a matrix filled with real or complex zeros.

In digital signal processing, complex numbers are common; it is
important to note that if complex_vals=False and complex values are
inserted into the matrix, the imaginary part will be removed.

Parameters
----------
shape : tuple or int
tuple or int indicating the shape or length of desired matrix or
vector, respectively
complex_vals : bool
indicator of whether or not the matrix will receive real or complex
values (default False)

Returns
----------
matrix : ndarray
a matrix filled with real or complex zeros

Examples
----------
>>> matrix = create_empty_matrix((3,4))
>>> matrix
array([[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]])
>>> matrix_complex = create_empty_matrix((3,4),complex_vals=True)
>>> matrix_complex
array([[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]])
>>> vector = create_empty_matrix(5,)
>>> vector
array([0., 0., 0., 0., 0.])
'''
if complex_vals:
matrix = np.zeros(shape, dtype=np.complex_)
else:
matrix = np.zeros(shape, dtype=float)
return matrix

[docs]def separate_dependent_var(matrix):
'''Separates matrix into features and labels.

Assumes the last column of the last dimension of the matrix constitutes
the dependent variable (labels), and all other columns the indpendent variables
(features). Additionally, it is assumed that for each block of data,
only one label is needed; therefore, just the first label is taken for
each block.

Parameters
----------
matrix : numpy.ndarray
The `matrix` holds the numerical data to separate

Returns
-------
X : numpy.ndarray
A matrix holding the (assumed) independent variables
y : numpy.ndarray, numpy.int64, numpy.float64
A vector holding the labels assigned to the independent variables.
If only one value in array, just the value inside is returned

Examples
--------
>>> import numpy as np
>>> #vector
>>> separate_dependent_var(np.array([1,2,3,4]))
(array([1, 2, 3]), 4)
>>> #simple matrix
>>> matrix = np.arange(4).reshape(2,2)
>>> matrix
array([[0, 1],
[2, 3]])
>>> X, y = separate_dependent_var(matrix)
>>> X
array([,
])
>>> y
1
>>> #more complex matrix
>>> matrix = np.arange(20).reshape((2,2,5))
>>> matrix
array([[[ 0,  1,  2,  3,  4],
[ 5,  6,  7,  8,  9]],
<BLANKLINE>
[[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]]])
>>> X, y = separate_dependent_var(matrix)
>>> X
array([[[ 0,  1,  2,  3],
[ 5,  6,  7,  8]],
<BLANKLINE>
[[10, 11, 12, 13],
[15, 16, 17, 18]]])
>>> y
array([ 4, 14])
'''
# get last column
y_step1 = np.take(matrix, -1, axis=-1)
# because the label is the same for each block of data, just need the first
# row,  not all the rows, as they are the same label.
y = np.take(y_step1, 0, axis=-1)
# get features:
X = np.delete(matrix, -1, axis=-1)
return X, y

if __name__ == "__main__":
import doctest
doctest.testmod()
```