tf-idf Features for Text
Once a text classifier has been trained, the natural question is which parts of the input it relied on.
Why Coefficients Matter After Training
Once a text classifier has been trained, the natural question is which parts of the input it relied on. When the classifier is a logistic regression model trained on tf-idf features, the answer lives in the model's coefficients. Each feature has a coefficient, and this article is about reading those coefficients.
A trained model can have hundreds or thousands of coefficients. A plain list of that many numbers is hard to read, so the practice shown in the source is to draw them as a bar chart. The chart makes the relative sizes of the coefficients visible at a glance. By the end of this article you should be comfortable reading that chart, knowing what each bar stands for, and tracing the small selection logic that decides which bars appear.
The selection logic is where beginners most often make mistakes, so we will go slowly through it. We will use a small made-up example, because the source chart itself cannot be re-run here and the feature names and values in our example are invented for illustration only.
Following Each Feature to Its Coefficient
The text is first turned into tf-idf features, which are extracted from the text using the tf-idf technique and then passed as input to the logistic regression model. The model learns one coefficient per feature from that input. A logistic regression coefficient is a learned number for each feature, and the source states that coefficients determine each feature's importance in the model.
Because there is exactly one coefficient for each tf-idf feature, each bar in the chart corresponds to one feature. The chart is therefore a view of the trained model, not a view of the raw text. Every bar you see can be traced back to a coefficient that the fitted model stored.
The diagram above uses invented terms and values. Its purpose is to show the alignment: position 0 in the feature names pairs with position 0 in the coefficient array, position 1 with position 1, and so on. If those positions were misaligned, each bar would be labeled with the wrong word.
The Call That Draws the Chart
The source produces the chart with a single call to a plotting helper named visualize_coefficients. The call does not compute anything on its own. It receives the coefficients and their names, and then draws them. Which coefficients appear is decided inside the helper, which is why the count parameter matters for what you see in the picture.
fitted_coefficients: the learned coefficient for each feature, taken from the trained modelfeature_names: the name of each tf-idf feature, in the same order as the coefficientsn_top_features=40: the count parameter that controls how many coefficients are drawn
Tracing a Sort-and-Slice Selection
The chart shows the largest and smallest coefficients, not the middle of the list. Picking out the extremes requires two operations in a specific order. First you sort the coefficients by value. Then you slice. Slicing an unsorted list selects by position, not by value, so the order of these two operations determines the result.
Here is a made-up example with five features. The names and values are invented and are not output from any real model. We pair each name with its value, sort the pairs by value, and then slice off the two lowest and the two highest. The middle of the list is simply left out, just as features with middle-sized values are not drawn in the chart.
[('bad', -1.2), ('boring', -0.5)]
[('good', 0.8), ('great', 1.5)]- zip pairs each name with its value so they stay together when sorting
- sorted with key=lambda p: p[1] orders the pairs by the value, not by the name
- [:2] takes the first two items of the sorted list, which are the two lowest values
- [-2:] takes the last two items of the sorted list, which are the two highest values
- movie, with value 0.1, is in the middle and is never selected
[('good', 0.8), ('bad', -1.2)]
[('boring', -0.5), ('great', 1.5)]- This version slices the unsorted pairs, so it selects by position in the original list
- good and bad are simply the first two features, not the two lowest values
- The result mixes a high value (0.8) into the low end, which the sorted version never does
What the Chart Shows and Leaves Out
A bar chart of the largest and smallest coefficients makes the relative sizes visible and lets you see the feature names alongside them. It does not tell you everything about importance. The table below separates what the chart displays from what it leaves out.
| Visible in the chart | Not shown by the chart |
|---|---|
| Feature names of the drawn coefficients | Coefficients of features that were left out of the selection |
| Relative sizes of the drawn coefficients | How the features perform on unseen data |
| Which drawn values are larger or smaller than others | Whether the middle of the ranking matters |
| The extremes selected by the helper | How the count parameter divides between the two ends, which the source does not settle |
What the bar chart of largest and smallest coefficients does and does not show
Mistakes When Reading Selection Logic
Common mistake Slicing the coefficients without sorting them first
What it looks likepairs[:2] on the made-up list returns good and bad, even though good has a high value of 0.8
Why it failsA slice selects by position in the list, not by the value stored at that position
Do this insteadSort the pairs by value with sorted(pairs, key=lambda p: p[1]) and only then take the first and last items
Common mistake Treating the middle of the list as hidden noise to be checked
What it looks likeAssuming movie, with value 0.1, is an unimportant feature because it is absent from the two-ended selection
Why it failsThe selection is only a view of the extremes, so a feature missing from the chart is not thereby shown to be unimportant or important
Do this insteadRemember the chart highlights the ends of the ranking and says nothing about the features it leaves out
Common mistake Assuming the chart reports performance on new text
What it looks likeReading a large bar as proof the feature improves predictions on unseen documents
Why it failsThe chart displays coefficients of the trained model, which is a view of the fitted model rather than an evaluation
Do this insteadUse the chart to see what the model relied on, and evaluate separately if you need to know how it performs on new data
Common mistake Ignoring the count parameter when interpreting how many bars appear
Predicting a Selection Before Running It
Using the same five made-up pairs (good 0.8, bad -1.2, movie 0.1, boring -0.5, great 1.5), work out the answer on paper before checking. Part one: what does sorting by value and then taking the first two items return? Part two: what does taking the last two items of the sorted list return? Part three: explain in one sentence why sorting has to come before slicing.
Hints
- Write the five values in order from smallest to largest first
- The two lowest values are the first two items of the sorted list
- Compare your answer with the output of the code in the example above
What do you think happens?
Without sorting, what does pairs[-2:] return from the original five pairs in order good, bad, movie, boring, great?
Reveal answer
boring and great
The original list ends with boring then great, so slicing the last two positions returns those two items. They are not the two highest values in this case only because of where they happen to sit; the position-based slice does not check value.
Key Takeaways
- A logistic regression coefficient is a learned number for each tf-idf feature, and the source states that coefficients determine each feature's importance in the model
visualize_coefficientsreceives the fitted coefficients, the feature names, and a count parameter, and then draws the selected bars; the source's call usesn_top_features=40- Selecting the largest and smallest coefficients requires sorting by value before slicing, because slicing an unsorted list selects by position
- The bar chart shows relative sizes and names of selected coefficients, but not performance on unseen data, and the source leaves the meaning of smallest and the split of the count parameter open