Visualizing Model Coefficients
A coefficient is the expected change in the target for a one-unit change in one input column.
Why a List of Numbers Can Be Read
A trained linear regression model is more than a prediction machine. It stores one number per input column, and those numbers are the coefficients. Reading them tells you what the model has learned about each input. The practical payoff is that you can often explain a model's behavior by looking at a short list of numbers, instead of treating the model as a black box.
This article follows one concrete case. An earlier step combined day-of-week and time-of-day inputs into interaction features. The resulting linear model performed about as well as a random forest on the same problem. Because the interaction features give one coefficient for each day and time combination, the whole model can be read directly off a plot of those coefficients. The job of this article is to read those coefficients correctly and to follow the small code steps that move them from the model into a plot.
What do you think happens?
The hour labels are created with range(0, 24, 3). How many labels does it produce, and which values are they?
Reveal answer
8 labels: 0, 3, 6, 9, 12, 15, 18, 21
range starts at zero, stops before 24, and steps by 3. The values 0, 3, 6, 9, 12, 15, 18 and 21 all fall below 24, and 24 itself is excluded because the stop value is not included. That gives 8 hour labels. The seven day abbreviations are a separate list, so a full set of day-and-hour combinations is built from 8 hours and 7 days.
What One Coefficient Stores
A coefficient is the expected change in the target for a one-unit change in one input column. The phrase 'one input column' matters: the change is measured for one feature at a time, while the other features are held fixed. A coefficient therefore describes the effect of a single input, not the total prediction.
In this formula, the coefficient for feature j is written as beta sub j. The expression says that if feature j goes up by exactly one unit and every other feature stays the same, the expected target moves by beta sub j. A positive coefficient means the expected target rises with that feature; a negative coefficient means it falls. The size of the coefficient tells you how large that movement is in the units of the target, so a coefficient of 2.0 means a one-unit increase is associated with a rise of about 2.0 in the expected target.
Keeping Names and Coefficients in Step
A coefficient list is only meaningful if you know which input each number belongs to. The code therefore builds a list of human-readable names for the original inputs. Here there are two groups: hour labels in steps of three hours across the day, and seven day abbreviations. The two lists are joined into one list of base feature names. The program then asks the transformer for the names of all the interaction features it generated, uses a boolean test on the learned coefficients to keep only the features whose coefficient is not zero, and extracts those nonzero coefficients as a separate list.
The diagram shows the key idea. The shaded positions, a and c, have zero coefficients and are removed. Position 1 and position 3 survive, and they survive in both lists at once. A name and its coefficient are linked only by their position index, so the mask must be applied to both lists. Because the model stores coefficients in one fixed order, the names are useful only when they sit at the same positions.
The filtering step relies on a NumPy idiom: comparing an array to a value produces an array of True and False, and indexing with that array keeps only the True positions. The example below uses made-up numbers, not output from the source model, so you can see the mask work in isolation.
['b' 'd']
[ 1.5 -2. ]- coefs != 0 produces an array of True and False, one value per position
- names[mask] keeps the names at the True positions
- coefs[mask] keeps the coefficients at the same True positions, so the pairing survives
Trace the output by position. The mask is False at positions 0 and 2, so 'a' and 'c' disappear from both arrays. The names 'b' and 'd' stay paired with 1.5 and negative 2.0 because both arrays were indexed with the same mask. If you had filtered only one of them, the pairing would be lost and the output would still look perfectly valid. This is why the mismatch is so dangerous: it rarely raises an error.
Reading a Coefficient Plot Without Being Misled
A plot is only as trustworthy as its labels. The plotting step draws one marker for each nonzero coefficient. It sets a wide, short figure so that many labels fit along one line, rotates the tick labels vertically so long names do not overlap, and places the feature names at the tick positions. The coefficient values are passed as the first and only data argument, so they are drawn on the vertical axis, while the feature names are placed on the horizontal axis through the tick settings.
The problem is that the axis labels in the plotting code are attached in an unexpected way. The horizontal axis is labeled as the feature magnitude, and the vertical axis is labeled as the feature. Read literally, those labels describe the opposite of what each axis shows. A reader who trusts the labels would conclude that the height of each marker is a feature name and that the horizontal position is a magnitude, which is wrong.
To locate the line responsible, compare the axis-label calls with the data arguments and tick settings in the same plotting function. The pack describes the labeling mechanism but does not show the exact source line, so you must find it yourself: look for the lines that set the horizontal and vertical axis labels, then trace each axis back to what it is actually given. If the labels and the data disagree, trust the data and correct the label before reading any conclusion from the plot.
Three Arguments to the Plotting Helper
The chart in the source is produced by a single call to a plotting helper named visualize_coefficients. The call takes three pieces of information. The excerpt relies on two names defined earlier in the original workflow, grid and feature_names, and the source does not show how they were created, so treat them as given inputs. The table below lists what each argument supplies.
| Argument | What it supplies | Where to look |
|---|---|---|
| First argument: the fitted coefficients | The learned numbers, one per feature, that the helper draws | Position 1 in the call |
| Second argument: feature_names | The names aligned by position with the coefficients | Position 2 in the call |
| Third argument: n_top_features=40 | A count parameter that controls how many coefficients the helper selects and draws | The keyword argument after the first two |
The three inputs to the plotting helper, as described in the source excerpt
Notice that the call does not compute anything on its own. It receives the coefficients and their names and then draws them. Selecting which coefficients appear is handled inside the helper, which is why the count parameter matters for what you see in the picture. Because the names are supplied separately, they must already be aligned with the coefficients, as covered in the earlier section on keeping names and coefficients in step.
Logistic Coefficients as Word Importance
Once a text classifier has been trained, the natural question is which parts of the input it relied on. In a logistic regression model trained on tf-idf features, each feature has a coefficient, and the source states that coefficients determine each feature's importance in the model. Here the features are tf-idf features, 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, so each bar in the chart corresponds to one tf-idf feature. The chart is therefore a view of the trained model, not of the raw text.
A list of hundreds or thousands of coefficients is hard to read, so the practice is to draw them as a bar chart. The chart makes the relative sizes of the coefficients visible at a glance. Larger bars mean a feature carries more weight in the model's decision. The sign of a coefficient indicates the direction in which that feature pushes the prediction. The source does not spell out which class each sign favors, so check that against the model's class ordering before reading a direction into a bar.
The source chart draws coefficient sizes for tf-idf features, produced by one call that takes the fitted coefficients, the feature names, and a count parameter. Read the chart from left to right in the pipeline sense: the text becomes tf-idf features, the model learns a coefficient for each feature, and the plotting helper turns those values into bars. Every bar you see is traceable back to a coefficient the fitted model stored.
Sorting Before Slicing
Picking the largest and smallest values requires sorting by the coefficient before slicing, since slicing an unsorted list selects by position, not by value. The source's invented example pairs each name with its value, sorts the pairs by value, and slices off the two lowest and two highest. The example below uses new made-up values, not output from any real model, to show the same idea.
Sort-then-slice versus slice-then-sort
Six invented coefficients are paired with names: a 0.4, b 1.5, c -0.3, d -2.0, e 0.9, f -0.8. Select the two lowest and two highest values, once by sorting first and once by slicing the unsorted list first.
- 1Sort the pairs by value
Ordering from smallest to largest gives d -2.0, f -0.8, c -0.3, a 0.4, e 0.9, b 1.5.
- 2Slice the sorted list
The first two items are d and f, which are the two lowest values. The last two items are e and b, which are the two highest values. The selection is d, f, e, b.
- 3Slice the unsorted list instead
In the original order a, b, c, d, e, f, the first two items are a and b, and the last two items are e and f. This selects by position, not by value.
- 4Compare the two selections
The wrong order returns a 0.4, b 1.5, e 0.9, f -0.8. It misses d -2.0, the smallest value, and includes a 0.4, which is not an extreme. Only the sort-first order selects the true extremes.
Sorting first returns d, f, e, b in that order. Slicing first returns a, b, e, f, which is not the largest and smallest selection.
The middle of the list is simply left out. This is the same idea behind a chart of the largest and smallest coefficients: features with values in the middle are not drawn, so the picture highlights the extremes of the ranking rather than every feature.
Mistakes That Distort the Chart
Common mistake Filtering the coefficients but not the feature names
What it looks likeApplying coefs != 0 to the coefficients and then pairing them with the full, unfiltered name list.
Why it failsThe positions no longer match, so each surviving number gets the label of a different feature. No error is raised.
Do this insteadBuild one mask and apply it to both the names and the coefficients.
Common mistake Trusting the axis labels without checking the data
What it looks likeReading the horizontal axis as a magnitude and the vertical axis as a feature name because the labels say so.
Why it failsThe labels are attached to the axes in a way that describes the opposite of what is plotted.
Do this insteadTrace each axis label back to the data argument or tick setting that drives it before reading the plot.
Common mistake Slicing an unsorted list to find the extremes
What it looks likeTaking the first two and last two items of the original order and calling them the lowest and highest coefficients.
Why it failsSlicing selects by position, not by value, so the items returned need not be extremes.
Do this insteadSort by the coefficient value first, then slice.
Common mistake Treating a large coefficient as a large feature value, when it describes the effect of a one-unit change
Common mistake Assuming the count parameter gives exactly 25 largest and 25 smallest bars without checking the helper
Predict the Selection Before You Run It
Six invented pairs are given: p 0.2, q -1.1, r 0.7, s -0.4, t 1.9, u -0.05. First predict which two items a sort-then-slice selection returns for the lowest two and the highest two, and in what order. Then predict what a slice-first selection on the original order returns. Explain in one sentence why the two results differ.
Hints
- Sort by the numeric value, not by the name, before taking any slice.
- The lowest two signed values are the two most negative numbers.
- A slice of the original list takes the first two and last two positions as written.
Key Takeaways
- A coefficient is the expected change in the target for a one-unit change in one input column, with the other inputs held fixed.
- Names and coefficients are linked only by position, so zero-valued coefficients must be removed from both lists with the same boolean mask.
- Axis labels on a coefficient plot must be checked against the data actually drawn, because swapped labels produce a confident but wrong reading.
- A logistic regression coefficient indicates how much weight a tf-idf word feature carries; a largest-and-smallest chart selects by sorting first and then slicing, and it leaves the middle of the ranking out.