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.
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?
Reveal 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.
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.
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.
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.
- 1Rows: 25000 training reviews, one row each
- 2Columns: 74849 vocabulary tokens, one column each
- 3Total cells: $25000 \times 74849 = 1871225000$
- 4Stored elements: $3431196$, the non-zero entries kept by the sparse format
- 5Fraction 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.
(2, 4)
[[0 2 1 1]
[1 0 1 0]]- 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.
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?
- 1Count the rows
Each row is one review, so two reviews give 2 rows.
- 2Learn the vocabulary
fit collects the distinct words good, movie, plot, and bad, so there are 4 columns.
- 3Count row one
good appears twice, movie once, plot once, and bad zero times, giving 0 2 1 1.
- 4Count row two
bad appears once, movie once, and good and plot zero times, giving 1 0 1 0.
- 5Count 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.
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 likeSeeing 74849 columns and assuming the training list must have 74849 reviews
Why it failsColumns track distinct vocabulary tokens, not documents. Rows track reviews.
Do this insteadRead rows as reviews and columns as vocabulary tokens, then check each against its own count.
Common mistake Calling transform before fit
What it looks likeRunning transform on the reviews before the vocabulary has been learned
Why it failsTransform fills columns from the learned vocabulary. Before fit there are no columns to fill.
Do this insteadRun 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 likeReading 3431196 and concluding the matrix has about 3.4 million rows
Why it failsThe stored element count is the number of non-zero entries kept by the sparse format, not a dimension.
Do this insteadTake 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.
- 1Check the shape first: the row count should equal the number of reviews, and the column count should equal the vocabulary size
- 2Check the order of fit and transform: transform must come after fit, and it must use the vocabulary fit learned
- 3Check which text was used to learn the vocabulary: the columns only mean what fit's text said they mean
Predict Before You Run
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
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.