Concepts / Decision Function in Binary Classification

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.

  • Programming

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.

Key point

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.

Decision valuee.g. -3.0Value greater than 0?strict comparisonTruebecomes index 1classes_ lookupselect the label by indexPredicted classone class nameFalsebecomes index 0yesno
How does a single signed score pass through the zero threshold and then select a class name from classes_?
Worked example

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?

  1. 1
    Compare -3.0 with zero

    -3.0 is not greater than zero, so it becomes False.

  2. 2
    Compare 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.

  3. 3
    Compare 4.0 with zero

    4.0 is greater than zero, so it becomes True.

  4. 4
    Collect 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.

Result

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_?

  • Index 0, the negative class

  • Index 1, the positive class

Reveal answer
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.

python
Output (expected)
['no' 'no' 'yes']
Notes on the code
  • 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
Key point

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.

Decision valuesone real number per sampleThreshold at zerokeep only the sign, strictgreater-thanBoolean maskone True or False persampleclasses_ lookupFalse to index 0, True toindex 1Compare with predictfirst mismatch marks thefailing stage
At which stage in the recovery pipeline does the reconstructed prediction stop matching model.predict?
  • Common mistake

    Reading decision values as percentages

    What it looks like

    Treating a value of 4 as a 4 percent chance, or as strong confidence on a zero-to-one scale.

    Why it fails

    The values are real-valued scores whose range depends on the data and model parameters.

    Do this instead

    Use 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 like

    Thresholding with scores >= 0 makes the value 0.0 True, so it maps to index 1 instead of index 0.

    Why it fails

    The recovery rule uses a strict comparison, so 0.0 belongs on the False side.

    Do this instead

    Use 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 like

    Reading index 1 as the label you expect, when classes_ actually lists the other class second.

    Why it fails

    The labels come from the classes_ attribute, not from your assumptions about the problem.

    Do this instead

    Print 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.

sample 0, class 0-1.2sample 1, class 01.1sample 0: class 2row maximumsample 0, class 10.3sample 1, class 1-0.4sample 1: class 0row maximumsample 0, class 22.5sample 1, class 20.0argmax axis=1argmax axis=1
What does each row and each column of the multiclass decision_function array represent, and how does argmax along axis=1 pick one column per row?

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.

python
Output (expected)
[2 0]
Notes on the code
  • 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
Best practice

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.

Shape(n_samples, n_classes)Meaningreal-valued certainty scoreper classRow totalnot stated to sum to 1Shape(n_samples, n_classes)Meaningprobability per classRow totaleach data point sums to 1
How do the shape and the meaning of decision_function output differ from predict_proba output for the same samples?
Propertydecision_functionpredict_proba
Shape(n_samples, n_classes)(n_samples, n_classes)
ValuesReal-valued certainty scoresProbabilities per class
Row sumsNot stated to sum to 1Each data point's values sum to 1
Ranking useLarger value means more likely within a rowLarger value means more likely within a row
ScaleDepends on data and model parametersInterpretable 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

EASY

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_function are 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), and np.argmax with 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_function and predict_proba share the same shape but differ in meaning: predict_proba values are probabilities that sum to 1 per data point, while decision values are not calibrated probabilities.

Related concepts

More concepts starting with D