Decision Function in Binary Classification
The numbers from decision_function are real-valued scores whose range depends on the data and model parameters, so they are not percentages or probabilities.
Why Raw Scores Look Like Percentages
Suppose a classifier's decision_function returns a value of 4 for one sample and a value of -3 for another. It is tempting to read these as confidence percentages, as if 4 means strong agreement and -3 means weak disagreement, with the scale running from zero to one or from zero to one hundred. This is the most common first reaction to decision_function output, and it is the misconception this article corrects.
The numbers are real-valued scores. The scale they live on is not fixed in advance. Their sign carries the decision between the two classes, while their magnitude tells you something about how far a sample sits from the separating rule. It does not give a calibrated chance that the classifier is right. The traps you will meet later in this article all grow out of the percentage reading, so keep it in mind as we work through the mechanism.
What the Scale Really Means
The range of decision_function is not fixed. It depends on the training data and on the model's parameters. The same classifier trained on a different dataset can produce scores that run over a completely different interval, and a score of 2 from one model does not mean the same thing as a score of 2 from another model. Because of this arbitrary scaling, the raw output is hard to interpret on its own.
What you can rely on is the sign. Positive values fall on one side of the decision rule and negative values fall on the other.
The exact size of a value is useful for ranking samples relative to one another within a single model. It does not convert into a probability without a separate calibration step, and that step is outside the scope of this section. In practice this means you can say that one sample sits further from the boundary than another, but you cannot say that one sample has a 90 percent chance of belonging to its class.
Tracing a Score Through the Zero Threshold
To recover the predicted class, you compare every decision value with zero. Values strictly greater than zero become True, and everything else becomes False. The result is a boolean array with one entry per sample. This is the core move of the whole mechanism: the sign of the score is the only information needed to choose between the two classes, and the magnitude is discarded at this step.
Tracing three scores through the threshold
A binary model returns the decision values -3.0, 0.0, and 4.0 for three samples. Which samples become True and which become False?
- 1Compare -3.0 with zero
-3.0 is not greater than zero, so it becomes False.
- 2Compare 0.0 with zero
0.0 is equal to zero, not strictly greater than it, so it also becomes False. This is the boundary case the strict comparison handles deliberately.
- 3Compare 4.0 with zero
4.0 is greater than zero, so it becomes True.
- 4Collect the boolean array
The result is one boolean per sample: False, False, True. The magnitudes 3.0 and 4.0 played no role beyond their signs.
The boolean mask is [False, False, True]. The magnitudes were discarded, and only the sign and the strict comparison decided each entry.
What do you think happens?
A decision value is exactly 0.0. After thresholding at zero, which index does it select from classes_?
Reveal answer
Index 0, the negative class
The rule keeps only values strictly greater than zero as True. A value of 0.0 is not strictly greater than zero, so it lands on the False side and maps to index 0.
Mapping Booleans onto classes_
A boolean is not yet a class name. For binary classification, the negative class is always the first entry of the classes_ attribute, and the positive class is the second entry. To reproduce the output of predict, you convert the booleans into the integers 0 and 1, then use those integers as indices into classes_. Index 0 selects the negative class and index 1 selects the positive class.
['no' 'no' 'yes']- scores > 0 applies the strict threshold and produces a boolean array
astype(int)converts False to 0 and True to 1- classes[indices] uses those integers to select the label for each sample
The order of classes_ is the whole story. Index 0 is always the negative class and index 1 is always the positive class, so the labels you recover depend entirely on that order being what you expect.
Finding Where a Recovery Goes Wrong
When your recovered labels disagree with predict, the fix is to check the stages in order and stop at the first one that diverges. For binary classification the stages are the decision values, the threshold, the boolean mask, and the classes_ lookup. Comparing your output with model.predict after each stage tells you which one broke.
Common mistake Reading decision values as percentages
What it looks likeTreating a value of 4 as a 4 percent chance, or as strong confidence on a zero-to-one scale.
Why it failsThe values are real-valued scores whose range depends on the data and model parameters.
Do this insteadUse the sign to decide the class, and use magnitudes only to rank samples within one model.
Common mistake Using greater-than-or-equal instead of strictly greater-than
What it looks likeThresholding with scores >= 0 makes the value 0.0 True, so it maps to index 1 instead of index 0.
Why it failsThe recovery rule uses a strict comparison, so 0.0 belongs on the False side.
Do this insteadUse scores > 0 and check exact zeros when a recovered label disagrees with predict.
Common mistake Assuming the class order is fixed by the data you have in mind
What it looks likeReading index 1 as the label you expect, when classes_ actually lists the other class second.
Why it failsThe labels come from the classes_ attribute, not from your assumptions about the problem.
Do this insteadPrint classes_ and confirm which label sits at index 0 and which at index 1 before mapping.
Reading a Multiclass Decision Function
In the multiclass case the decision function has the shape $(n_{\text{samples}}, n_{\text{classes}})$. Each row corresponds to one data point and each column corresponds to one class. The value in a given cell is a certainty score for that class on that data point. The column order follows the class labels the classifier learned, so column 0 is the score for class 0, column 1 for class 1, and column 2 for class 2. The shape alone tells you how many classes exist.
Read the rows one at a time. For a single data point you compare the scores across its columns, and the class whose column holds the largest value is the one the classifier considers most likely. The rule is comparative. What matters is which column is largest within a row, not whether any single number clears some fixed threshold. In the small example above, sample 0 has its largest score in column 2, and sample 1 has its largest score in column 0.
Because the largest entry in each row marks the most likely class, predictions can be recovered directly from the decision function. You find the index of the maximum entry for each data point with np.argmax(scores, axis=1), which returns, for every row, the column index where that row's maximum sits.
[2 0]- Each row is one data point and each column is one class
- axis=1 compares across the columns within each row
- The result holds one column index per data point, which is the predicted class index
When a multiclass prediction looks wrong, check the stages in order. First confirm the shape of the decision function. Then confirm that the argmax runs across axis 1. Finally compare your recovered predictions with model.predict on the same data. If the arrays disagree, the divergence is in the argmax step or in how the rows were prepared, not in the classifier itself.
Decision Function versus predict_proba
The predict_proba method also produces one value per class for each data point. Its output has the same shape as the decision function, $(n_{\text{samples}}, n_{\text{classes}})$, so the two arrays are laid out the same way. They are not the same quantity, and the difference is what matters when you interpret them.
| Property | decision_function | predict_proba |
|---|---|---|
| Shape | (n_samples, n_classes) | (n_samples, n_classes) |
| Values | Real-valued certainty scores | Probabilities per class |
| Row sums | Not stated to sum to 1 | Each data point's values sum to 1 |
| Ranking use | Larger value means more likely within a row | Larger value means more likely within a row |
| Scale | Depends on data and model parameters | Interpretable as probabilities |
Both outputs share a layout, but only predict_proba is described as summing to 1 per data point.
Because the shapes match, it is easy to assume the numbers can be swapped. They cannot. A decision value of 2.5 does not mean the same thing as a probability of 0.5, and the decision function does not carry the sum-to-one guarantee that predict_proba does.
Practice Recovering Labels
A binary model has classes_ equal to ['cat', 'dog']. Its decision values for four samples are [-0.5, 0.0, 2.2, -1.7]. Recover the predicted label for each sample by thresholding at zero with a strict greater-than comparison, then mapping the booleans through classes_.
Hints
- Compare each value with zero using strictly greater-than, so the value 0.0 does not count as True
- False maps to index 0 and True maps to index 1
- Index 0 is cat and index 1 is dog
Key Takeaways
- The numbers from
decision_functionare real-valued scores whose range depends on the data and the model, so they are not percentages or probabilities. Only the sign is reliable for the decision, and magnitudes rank samples within one model. - For binary classification, values strictly greater than zero become True, and the boolean mapped through classes_ (index 0 for False, index 1 for True) reproduces predict.
- In the multiclass case the decision function has shape (
n_samples,n_classes), andnp.argmaxwith axis=1 picks the column with the largest score in each row as the predicted class. - When recovery disagrees with predict, check the scores, the threshold, the mask, and the class order in sequence to find the first step that diverges.
decision_functionandpredict_probashare the same shape but differ in meaning:predict_probavalues are probabilities that sum to 1 per data point, while decision values are not calibrated probabilities.