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 ...
... ... ... ... ... ... ... ... ...