All about matrices

One of the most common classes you will deal with when using the nephosem module (and by extension semasioFlow) is TypeTokenMatrix, which covers both type-level and token-level matrices, either for raw co-occurrences, association matrices or even square distance/similarity matrices. Here you can learn a bit about what you can do with them.

[1]:
import sys
nephosemdir = "../../nephosem/"
sys.path.append(nephosemdir)
mydir = f"./"
from nephosem import ConfigLoader, TypeTokenMatrix
conf = ConfigLoader()
settings = conf.update_config('config.ini')

Matrices and files

Like Vocab objects (see here), TypeTokenMatrix objects have load() and save() methods:

[2]:
filename = 'output/Toy.bow.wcmx.pac'
mtx = TypeTokenMatrix.load(filename) # opens a matrix
mtx
# mtx.save(filename) # saves the matrix
[2]:
[55, 55]  's/P  ,/,  a/D  about/I  about/R  all/P  an/D  ...
's/P      NaN   NaN  NaN  NaN      NaN      NaN    NaN   ...
,/,       NaN   2    2    NaN      NaN      NaN    NaN   ...
a/D       NaN   2    NaN  NaN      NaN      NaN    NaN   ...
about/I   NaN   NaN  NaN  NaN      NaN      NaN    NaN   ...
about/R   NaN   NaN  NaN  NaN      NaN      NaN    NaN   ...
all/P     NaN   NaN  NaN  NaN      NaN      NaN    NaN   ...
an/D      NaN   NaN  NaN  NaN      NaN      NaN    NaN   ...
...       ...   ...  ...  ...      ...      ...    ...   ...

This will create an .npy and a .meta files and compress them together in a .pac file (like .zip, basically). You can also store them as comma-separated values with mtx.to_csv(filename). Why would you do that? If you want to open a type-level matrix in R, it doesn’t work unless it’s stored as .csv.

Matrix components

A TypeTokenMatrix has row names, column names and a numpy matrix element, all retrievable with corresponding attributes:

[3]:
mymatrix = mtx.matrix # returns a numpy 2D array
mymatrix
[3]:
<55x55 sparse matrix of type '<class 'numpy.int64'>'
        with 606 stored elements in Compressed Sparse Row format>
[4]:
rows = mtx.row_items # returns a list
rows[:5]
[4]:
["'s/P", ',/,', 'a/D', 'about/I', 'about/R']
[5]:
columns = mtx.col_items # returns a list
columns[:5]
[5]:
["'s/P", ',/,', 'a/D', 'about/I', 'about/R']
[6]:
mtx2 = TypeTokenMatrix(matrix = mymatrix, row_items = rows, col_items = columns) # creates a matrix again
mtx2
[6]:
[55, 55]  's/P  ,/,  a/D  about/I  about/R  all/P  an/D  ...
's/P      NaN   NaN  NaN  NaN      NaN      NaN    NaN   ...
,/,       NaN   2    2    NaN      NaN      NaN    NaN   ...
a/D       NaN   2    NaN  NaN      NaN      NaN    NaN   ...
about/I   NaN   NaN  NaN  NaN      NaN      NaN    NaN   ...
about/R   NaN   NaN  NaN  NaN      NaN      NaN    NaN   ...
all/P     NaN   NaN  NaN  NaN      NaN      NaN    NaN   ...
an/D      NaN   NaN  NaN  NaN      NaN      NaN    NaN   ...
...       ...   ...  ...  ...      ...      ...    ...   ...

In addition, the sum() method gives you marginal frequencies: of the rows for mtx.sum(axis=1), of the columns for mtx.sum(axis=2) and the full sum otherwise. You can use them, transformed to Vocab objects, as marginal frequencies for compute_association() (when weighting matrices):

[7]:
type(mtx.sum(axis=1))
[7]:
dict

Subsetting a matrix

You can subset a matrix with the submatrix() method, specifying a list of rows and/or a list of columns. Non-existing items will simply be ignored.

[8]:
rows = ['girl/N', 'boy/N', 'apple/N']
cols = ['give/V', 'eat/V', 'ask/V']
[9]:
subset_rows = mtx.submatrix(row = rows)
subset_rows
[9]:
[3, 55]  's/P  ,/,  a/D  about/I  about/R  all/P  an/D  ...
girl/N   1     1    5    1        1        NaN    NaN   ...
boy/N    NaN   NaN  4    1        NaN      1      3     ...
apple/N  1     1    4    1        1        NaN    3     ...
[10]:
subset_cols = mtx.submatrix(col = cols)
subset_cols
[10]:
[55, 3]  give/V  eat/V  ask/V
's/P     NaN     NaN    NaN
,/,      NaN     1      NaN
a/D      2       1      NaN
about/I  NaN     1      1
about/R  NaN     1      NaN
all/P    NaN     NaN    NaN
an/D     1       2      NaN
...      ...     ...    ...
[11]:
subset_both = mtx.submatrix(row = rows, col = cols)
subset_both
[11]:
[3, 3]   give/V  eat/V  ask/V
girl/N   4       11     1
boy/N    5       10     1
apple/N  2       12     NaN

You can also easily drop all empty rows/columns with the drop() method. So, for example, if you have subsetted your matrix by rows and now some columns are empty in all remaining rows, you can clean them out like so:

[12]:
mtx.submatrix(row = ['about/R']).drop(axis = 1)
[12]:
[1, 5]   apple/N  eat/V  girl/N  ten/J  the/D
about/R  1        1      1       1      1
[13]:
subset_cols.drop(axis = 0) #drops empty rows
[13]:
[43, 3]  give/V  eat/V  ask/V
,/,      NaN     1      NaN
a/D      2       1      NaN
about/I  NaN     1      1
about/R  NaN     1      NaN
an/D     1       2      NaN
and/C    NaN     4      NaN
apple/N  2       12     NaN
...      ...     ...    ...
[14]:
subset_cols.drop(axis = 0, n_nonzero = 1) # drops rows that only have one non-zero value or less
[14]:
[13, 3]  give/V  eat/V  ask/V
a/D      2       1      NaN
about/I  NaN     1      1
an/D     1       2      NaN
apple/N  2       12     NaN
be/V     2       6      NaN
boy/N    5       10     1
by/I     1       3      NaN
...      ...     ...    ...

If you just want to obtain the value for a given row-column combination, you can simply subset with square brackets.

[15]:
mtx['apple/N','girl/N']
[15]:
10

Boolean filter

You can use any boolean matrix with the same dimensions to filter, for example, cells with certain values. The code below returns a boolean matrix with True where the values are larger than 1 and False where they are not (but NaN where it was NaN).

[16]:
mtx > 1
[16]:
[55, 55]  's/P  ,/,   a/D   about/I  about/R  all/P  an/D  ...
's/P      NaN   NaN   NaN   NaN      NaN      NaN    NaN   ...
,/,       NaN   True  True  NaN      NaN      NaN    NaN   ...
a/D       NaN   True  NaN   NaN      NaN      NaN    NaN   ...
about/I   NaN   NaN   NaN   NaN      NaN      NaN    NaN   ...
about/R   NaN   NaN   NaN   NaN      NaN      NaN    NaN   ...
all/P     NaN   NaN   NaN   NaN      NaN      NaN    NaN   ...
an/D      NaN   NaN   NaN   NaN      NaN      NaN    NaN   ...
...       ...   ...   ...   ...      ...      ...    ...   ...

Such a matrix can be used to turn all the values below that threshold into 0s with the multiply() method.

[17]:
mtx.multiply(mtx > 1).drop(axis = 1).drop(axis = 0)
[17]:
[35, 35]  ,/,  a/D  an/D  and/C  apple/N  ask/V  at/I  ...
,/,       2    2    NaN   NaN    NaN      NaN    NaN   ...
a/D       2    NaN  NaN   2      4        NaN    2     ...
an/D      NaN  NaN  NaN   NaN    3        NaN    NaN   ...
and/C     NaN  2    NaN   NaN    3        NaN    NaN   ...
apple/N   NaN  4    3     3      NaN      NaN    NaN   ...
ask/V     NaN  NaN  NaN   NaN    NaN      NaN    NaN   ...
at/I      NaN  2    NaN   NaN    NaN      NaN    NaN   ...
...       ...  ...  ...   ...    ...      ...    ...   ...