Concepts / Introduction to Classifier Uncertainty

Introduction to Classifier Uncertainty

The decision function for multiclass classification has shape (n_samples, n_classes), with one certainty score per class for each data point.

  • Programming

Why a Classifier Can Say More Than Its Answer

A classifier that predicts one of several classes does not have to reveal only its final answer. Behind each prediction it has scored every possible class, and some classifiers expose those internal scores through a method called decision_function. Instead of asking only what the classifier predicts, this article asks what the classifier is weighing when it makes that prediction.

The running setting is a gradient boosted classifier trained on the Iris dataset, which has three classes. After training, we ask this classifier for its decision function on the test set. Before reading the numbers, predict what kind of output you expect: one number per data point, one number per class, or something else.

What do you think happens?

For a test set of several flowers and three classes, how many numbers do you expect decision_function to return for each flower?

  • One number, the predicted class label

  • Three numbers, one score per class

  • A single probability for the most likely class

Reveal answer
Answer:

Three numbers, one score per class

In the multiclass case the decision function has shape (n_samples, n_classes), so each data point gets one certainty score for every class. With three classes, each row has three values.

Reading the Shape of the Scores

The decision function for multiclass classification has shape $(n_{\text{samples}}, n_{\text{classes}})$. Each row corresponds to one data point, and each column corresponds to one class. The value stored in a given cell is a certainty score for that class on that data point.

row 0, column 0score for class 0 on point0row 1, column 0score for class 0 on point1row 0, column 1score for class 1 on point0row 1, column 1score for class 1 on point1row 0, column 2score for class 2 on point0row 1, column 2score for class 2 on point1
Which axis indexes the samples and which indexes the classes? Each row belongs to one data point, and each cell in that row is a score for one class.

Column order follows the class labels the classifier learned. Column 0 holds the score for class 0, column 1 for class 1, and column 2 for class 2. The number of columns tells you how many classes exist, and the column positions tell you which label each score belongs to. Keep this mapping in mind whenever you debug, because a score in the wrong column is a labeling error, not a model error.

Scores as Certainty Within a Row

A larger certainty score means a class is more likely, and a smaller score means it is less likely. To interpret a data point, read its row one at a time and compare the scores across its columns. The class whose column holds the largest value is the one the classifier considers most likely for that point.

class 0-1.2class 10.4class 22.1
Within one data point's row, which class has the largest score? The comparison inside the row decides the most likely class, not whether any single number crosses a fixed threshold.

The example row above is a made-up row, chosen only to practice reading scores. It is not output from a real model. Class 2 has the largest value, so it is the class this row favors. Notice that the rule is comparative. The raw values -1.2 and 0.4 are not wrong or invalid simply because they are below some cutoff; they are simply smaller than 2.1 in the same row.

Recovering the Predicted Class with argmax

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. The NumPy call np.argmax(scores, axis=1) does this. It returns, for every row, the column index where that row's maximum sits.

column 0-1.2argmax result: 2predicted class indexcolumn 10.4column 22.1 (maximum)returns index
For this row, which column has the largest score, and what column index does np.argmax return for it?
python
Notes on the code
  • scores has shape (n_samples, n_classes); one row per test point
  • axis=1 takes the maximum across each row, i.e. across the classes
  • comparing with gbrt.predict checks that the recovered classes agree entry for entry

The source runs this same kind of check: it prints the argmax of the decision function and the output of gbrt.predict on the same test set, and the two arrays match entry for entry. For this classifier, then, the predicted class is the column with the maximum certainty score in each row. The mapping from column index back to class label works here because the classes are labeled 0, 1, and 2 in the order the classifier learned them.

Worked example

Recovering one prediction by hand

A single data point has the decision function row [-1.2, 0.4, 2.1]. Which class does the classifier predict for this point?

  1. 1
    Identify the row

    The row has three values, one per class, so this is one data point in a three-class problem.

  2. 2
    Find the maximum

    The largest value is 2.1, which sits in column 2.

  3. 3
    Apply argmax along axis 1

    np.argmax over this row returns the index 2, the column where the maximum sits.

  4. 4
    Map the index to a class

    Column 2 is the score for class 2, so the predicted class for this point is class 2.

Result

The predicted class is 2, because column 2 holds the largest certainty score in the row.

Decision Function Versus predict_proba

Another method, predict_proba, also returns 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 outputs are laid out the same way. They are not the same quantity, though. The decision function gives certainty scores, while predict_proba gives probabilities whose values for each data point sum to 1. The source does not state that the decision function's values sum to 1, so do not assume it.

Shape(n_samples, n_classes)Shape(n_samples, n_classes)Meaningcertainty score per classMeaningprobability per classRow sums to 1not stated by the sourceRow sums to 1yes, per data point
When given the same samples, how do the two outputs differ in shape, value range, and meaning?

Mistakes When Reading Decision Function Output

  • Common mistake

    Taking the argmax across the wrong axis

    What it looks like

    Calling np.argmax(scores) with no axis argument, which searches the whole array rather than each row.

    Why it fails

    The prediction is defined per data point, so the maximum must be found within each row across the classes.

    Do this instead

    Use np.argmax(scores, axis=1) so that each row returns the index of its own largest score.

  • Common mistake

    Reading a column index as the class label without checking the mapping

    What it looks like

    Assuming column 2 always means class 2 without checking which labels the classifier learned.

    Why it fails

    Column order follows the learned class labels, so the mapping from column to label should be confirmed rather than assumed.

    Do this instead

    Confirm the learned class order before translating an argmax index into a label.

  • Common mistake

    Treating decision function values as probabilities

    What it looks like

    Concluding that a score of 2.1 means a 210 percent chance of a class.

    Why it fails

    The decision function gives certainty scores that are compared within a row. The source does not describe them as probabilities.

    Do this instead

    Compare scores within the row to find the most likely class, and use predict_proba if you need probabilities that sum to 1.

  • Common mistake

    Judging a score only by whether it is above a fixed cutoff instead of comparing it with the other scores in its row

Debugging a Two-Step Pipeline

The decision function followed by argmax is a two-step pipeline, so you can check each step separately when a prediction looks wrong. First confirm the shape of the decision function. Then confirm that the argmax runs across axis 1. Finally, compare the recovered predictions with gbrt.predict on the same data. If the two arrays disagree, the divergence lies in the argmax step or in how the rows were prepared, not in the classifier itself.

MEDIUM

A colleague reports that their recovered predictions do not match gbrt.predict. Their decision function has shape (n_samples, 3), and they call np.argmax(scores) without an axis argument. Using the three-step check described above, which step is most likely the source of the mismatch, and what single change would fix it?

Hints
  • Start with the shape check. Does the shape look correct for a three-class problem?
  • Then look at the axis argument. What does omitting axis do to a two-dimensional array?
  • The fix is a change to the argmax call, not to the classifier.

Key Takeaways

  • The decision function for a multiclass classifier has shape (n_samples, n_classes): each row is one data point and each column is one class.
  • Each cell is a certainty score, and a larger score means a class is more likely, so you compare scores within each row rather than against a fixed threshold.
  • np.argmax(scores, axis=1) returns the column index of the largest score in each row, which for this classifier matched gbrt.predict in the source example.
  • predict_proba has the same shape as the decision function but gives per-data-point probabilities that sum to 1, while the decision function is not stated to do so, so the two should not be interpreted the same way.

Related concepts

More concepts starting with I