Concepts / Sparse Matrix Representation

Sparse Matrix Representation

The full training matrix is too large to inspect by hand, so this worked example runs the same pipeline on a two-review corpus.

  • Programming

A Matrix Mostly Made of Zeros

This article follows a sentiment analysis task: deciding whether a movie review expresses a positive or negative opinion. The reviews come from the IMDb dataset and were loaded earlier into two lists of strings, one for training and one for testing. Each string is an entire review. A computer cannot work with the words of a review directly, so the bag-of-words process gives each review a numeric form based on which words occur in it and how often.

The scale is what changes compared with the small examples earlier in the chapter. The training list holds 25000 reviews, so the numeric representation has to handle a large collection. The result turns out to be stored in a special format designed for matrices that are mostly zeros. Understanding why that format exists, and how to read what it prints, is the goal of this article.

What do you think happens?

Before reading on: how many rows and columns would you expect the training matrix built from the 25000 reviews to have?

  • 25000 rows and 25000 columns

  • 25000 rows, with one column per review word, so the column count depends on the vocabulary

  • 74849 rows and 25000 columns

Reveal answer
Answer:

25000 rows and 74849 columns

Each row is one review, so the 25000 training reviews give 25000 rows. The columns track distinct tokens in the vocabulary that fit learned, not reviews, so there are 74849 columns.

Storing Only the Non-Zero Cells

A sparse matrix representation stores only the non-zero elements of a matrix rather than every cell. The format is meant for large matrices that contain many zero elements. A dense alternative would keep a slot for every cell. In the review-by-word setting, that means a slot for every word in every review, including the many words that never appear in that review.

The diagram below takes one review and lays out its row cell by cell. Each cell is a vocabulary word. The count for that word in this review is shown beneath it. Cells with a count above zero are the ones a sparse format keeps. The zero cells are the empty space a dense layout would still pay for.

badcount 0goodcount 2moviecount 1plotcount 1
Of the cells in this review's row, which ones a sparse format keeps, and which zero cells a dense layout would still store?

The cells marked as changed are the stored non-zero entries. The zero cell for bad is the kind of entry a sparse format does not need to keep. In a four-word toy vocabulary the saving is small. In a real collection with tens of thousands of vocabulary words, most word-review combinations are zero, so the saving becomes large.

How fit and transform Divide the Work

The work happens in two separate steps. The fit step is applied to the training text and learns which tokens exist in the collection. It builds a vocabulary and remembers it. The transform step then uses that learned vocabulary to convert text into counts, producing one row per review. The two steps have different jobs, and the order between them matters.

Definition

CountVectorizer applies fit to learn a vocabulary from text and transform to produce a matrix of token counts, with one row per review.

In the course source, the training reviews pass through both steps in one line, and the result is stored in a variable named X_train. The name X is the usual convention for the matrix of inputs a model learns from. The sentiment labels, which say whether each review is positive or negative, are a separate target and are not part of this step. The diagram below shows the messages passed between the stages.

Training reviews25000 stringsfitlearns tokensVocabularyremembered column listtransformcounts each reviewX_trainmatrix of token countstext defines vocabularystores learned tokenssupplies columnssame text is countedone row per review
What does fit build and remember from the training reviews, and what does transform do with that vocabulary?

Reading the Printed Matrix Summary

The source prints the matrix using a representation string with three pieces of information: the dimensions of the matrix, the data type of its values, and the storage format. For the training matrix the dimensions read 25000x74849. The rows match the 25000 training reviews, so each row represents one review. The columns equal the size of the vocabulary that fit learned from the training text.

The values have the type numpy.int64. This fits counts, because a count is a whole number. The same printout then reports that the matrix contains 3431196 stored elements in Compressed Sparse Row format. The stored element count is not the number of rows or columns and should not be read as the size of the matrix. It counts only the entries that the sparse format keeps.

Formula, step by step
  1. 1
    Rows: 25000 training reviews, one row each
  2. 2
    Columns: 74849 vocabulary tokens, one column each
  3. 3
    Total cells: $25000 \times 74849 = 1871225000$
  4. 4
    Stored elements: $3431196$, the non-zero entries kept by the sparse format
  5. 5
    Fraction stored: $\frac{3431196}{1871225000} \approx 0.18\%$ of the full grid

The stored fraction is about 0.18 percent of all cells. Nearly every word-review combination is zero, because most words never appear in most reviews. A dense matrix would store all 1871225000 cells, and almost all of that memory would hold zeros. The sparse format keeps only the 3431196 entries that carry counts.

Tracing a Two-Review Corpus

The full training matrix is too large to inspect by hand, so this worked example runs the same pipeline on a two-review corpus. The import line is not shown in the source excerpt, so it is added here. Read the program line by line and predict the printed matrix before checking the output.

python
Output (expected)
(2, 4)
[[0 2 1 1]
 [1 0 1 0]]
Notes on the code
  • The import line is added here because the source excerpt does not show it
  • fit reads the corpus and learns the four-word vocabulary
  • transform uses that vocabulary to count words in each review
  • toarray is used only to display the small matrix in full; the real matrix stays sparse

Before reading the output, predict its shape. The corpus has two reviews, so there should be two rows. The distinct words are good, movie, plot, and bad, so there should be four columns. The shape should therefore be 2 by 4. The printed matrix confirms it: row one counts good twice, movie once, and plot once, while bad is zero. Row two counts bad once and movie once.

badcount 0goodcount 2moviecount 1plotcount 1
Which column corresponds to which word, and how do the words in one review fill its row?
Worked example

Predicting and checking the two-review matrix

Given the corpus good movie good plot and bad movie, what shape and row values does the matrix have?

  1. 1
    Count the rows

    Each row is one review, so two reviews give 2 rows.

  2. 2
    Learn the vocabulary

    fit collects the distinct words good, movie, plot, and bad, so there are 4 columns.

  3. 3
    Count row one

    good appears twice, movie once, plot once, and bad zero times, giving 0 2 1 1.

  4. 4
    Count row two

    bad appears once, movie once, and good and plot zero times, giving 1 0 1 0.

  5. 5
    Count the stored entries

    Row one has 3 non-zero counts and row two has 2, so a sparse format would store 5 entries out of 8 cells.

Result

The matrix has shape 2 by 4 with rows 0 2 1 1 and 1 0 1 0. This toy matrix is far denser than the real one, which stores about 0.18 percent of its cells.

Where Pipelines Go Wrong

  • Common mistake

    Expecting the column count to equal the number of reviews

    What it looks like

    Seeing 74849 columns and assuming the training list must have 74849 reviews

    Why it fails

    Columns track distinct vocabulary tokens, not documents. Rows track reviews.

    Do this instead

    Read rows as reviews and columns as vocabulary tokens, then check each against its own count.

  • Common mistake

    Calling transform before fit

    What it looks like

    Running transform on the reviews before the vocabulary has been learned

    Why it fails

    Transform fills columns from the learned vocabulary. Before fit there are no columns to fill.

    Do this instead

    Run fit on the text that defines the vocabulary first, then transform.

  • Common mistake

    Treating the stored element count as the matrix size

    What it looks like

    Reading 3431196 and concluding the matrix has about 3.4 million rows

    Why it fails

    The stored element count is the number of non-zero entries kept by the sparse format, not a dimension.

    Do this instead

    Take the dimensions from the shape information and use the stored count only to judge how sparse the matrix is.

  • Common mistake

    Assuming a dense layout would be practical for 25000 reviews, when most of its cells would hold zeros

A less obvious mistake is fitting on one text and transforming a different one, then expecting the columns to line up. Transform uses the vocabulary that fit learned. If a second fit were run on different text, the vocabulary would change and the columns would no longer mean the same words. This is a general consequence of how the two steps depend on each other, applied here to the two-review example.

Checking a Pipeline That Looks Wrong

When the output of a bag-of-words pipeline does not match expectations, the source suggests a order of checks. Work through them in sequence, because the first check that fails usually points to the step where the output first diverged from what was expected.

  1. 1
    Check the shape first: the row count should equal the number of reviews, and the column count should equal the vocabulary size
  2. 2
    Check the order of fit and transform: transform must come after fit, and it must use the vocabulary fit learned
  3. 3
    Check which text was used to learn the vocabulary: the columns only mean what fit's text said they mean

Predict Before You Run

EASY

A corpus has three reviews: "great plot", "great acting", and "boring plot". Predict the shape of the matrix that CountVectorizer produces after fit and transform, assuming the reviews are treated as above. Write down your predicted rows and columns before checking the answer below.

Hints
  • Rows come from the number of reviews
  • Columns come from the number of distinct words in the corpus, not from the number of reviews
  • Count the distinct words across all three reviews: great, plot, acting, and boring
MEDIUM

Using the same three reviews, count how many cells a dense matrix would store and how many non-zero entries a sparse format would keep. Then state which of the two is smaller and why that gap grows with a larger corpus.

Hints
  • A dense matrix stores rows times columns cells
  • Count the non-zero counts row by row: great plot has two, great acting has two, boring plot has two
  • Think about what happens to the zero cells as the vocabulary grows across tens of thousands of words

At a glance

  • CountVectorizer uses fit to learn a vocabulary from text and transform to turn text into a matrix of token counts with one row per review.
  • The columns of the bag-of-words matrix track vocabulary tokens, so the 25000 training reviews give 25000 rows and 74849 columns, not 25000 columns.
  • A sparse matrix representation stores only the non-zero elements; the 25000 by 74849 training matrix stores 3431196 entries, about 0.18 percent of its cells.
  • Predict the shape from the number of reviews and the vocabulary size before running the code, and check the shape first when the output looks wrong.

Related concepts

More concepts starting with S