Abstractions csrmatrix - CyrilB1531/lodestar GitHub Wiki

HomeAbstractionsThe shared sparse primitive

CsrMatrix

The compressed-sparse-row matrix every vectorizer returns: one row per document, one column per feature, and only the non-zero entries stored.

A corpus of ten thousand documents over fifty thousand terms has five hundred million cells and perhaps a million non-zero ones. Storing the zeros is what this layout exists to avoid, and it is the same layout scipy.sparse.csr_matrix uses, so a reader who knows one knows the other.


public sealed class CsrMatrix

PropertiesRowCount and ColumnCount are the logical shape, zeros included. NonZeroCount is how many cells are actually stored. Values holds those cells, ColumnIndices the column each one sits in, and RowPointers where each row starts and ends: row i occupies Values[RowPointers[i]..RowPointers[i + 1]]. RowPointers therefore has RowCount + 1 entries, and its last is NonZeroCount.

Example — three documents, five terms, and the three arrays that describe them.

using Lodestar.Abstractions;
using Lodestar.Text.Vectorization;

string[] docs = ["the cat eats", "the dog eats", "the cat and the dog"];
CsrMatrix counts = new CountVectorizer().FitTransform(docs);

int rows = counts.RowCount;          // => 3
int columns = counts.ColumnCount;    // => 5
int stored = counts.NonZeroCount;    // => 10

// Row 2 runs from RowPointers[2] to RowPointers[3].
int start = counts.RowPointers[2];   // => 6
int end = counts.RowPointers[3];     // => 10

Remarks — fifteen cells, ten of them stored: the third document is the only one holding and, and the first two hold neither and nor one of cat/dog.

The three arrays are exposed rather than hidden because reading them is often the point — feeding another library, writing a file format, or checking what a vectorizer produced. They are the matrix's own double[] and int[], handed out without copying, so writing to one changes the matrix. Treat them as read-only unless that is precisely what you mean.

Within a row, ColumnIndices is ascending in every matrix this repository builds, but the constructor does not require it (decision 0003 left that invariant to a decision of its own). A column stored twice in one row counts as the sum of its entries in CsrMatrix.ToDense, CsrMatrix.Multiply and CsrMatrix.TransposeMultiply, which is how scipy.sparse.csr_matrix reads it. Lodestar.Preprocessing's three sparse fits sum them too, since sklearn.utils.sparsefuncs reduces through scipy. CsrMatrix.RowL1Norm, CsrMatrix.RowL2Norm and CsrMatrix.NormalizeRows do not: they treat each stored entry on its own, as sklearn.preprocessing.normalize does, so a row storing 1 and 2 in one column has an L2 norm of √5, not 3, where scipy.sparse.linalg.norm would sum them first.

Applies to — net10.0, netstandard2.0.

See alsoCountVectorizer, SparseNorm, the vectorization guide, the Python equivalence table.

Members

Member What it does
CsrMatrix.Multiply The matrix times a dense vector, or times a dense block.
CsrMatrix.TransposeMultiply The transposed matrix times a dense block, without building the transpose.
CsrMatrix.NormalizeRows Divide every row by its own norm, in place.
CsrMatrix.RowL1Norm The sum of one row's absolute values.
CsrMatrix.RowL2Norm The Euclidean length of one row.
CsrMatrix.ToDense The same matrix with its zeros written out.