Confusion Matrix
A confusion matrix counts a model's predictions against the true labels, class by class. How to read it, the metrics it yields, and its detection form.
A confusion matrix is a table that counts how a classification model's predictions line up with the true labels. One axis lists the actual classes and the other the predicted classes, and each cell counts the examples that fall into that pair. Correct predictions land on the diagonal, and every mistake lands off it, in the cell that names exactly which class was mistaken for which. That makes the confusion matrix the standard first view of a model's errors and the source of accuracy, precision, recall, and the F1-score.
Reading a Binary Confusion Matrix#
With two classes, the matrix has four cells:
- True positives (TP): positive examples predicted as positive, such as a defective part flagged as defective.
- False positives (FP): negative examples predicted as positive, also called Type I errors or false alarms.
- False negatives (FN): positive examples predicted as negative, also called Type II errors or misses.
- True negatives (TN): negative examples predicted as negative.
Most binary metrics are ratios of these four counts. Precision is TP / (TP + FP), recall is TP / (TP + FN), and accuracy is (TP + TN) divided by all four. Which off-diagonal cell matters more depends on the application: a cancer screen is tuned to keep false negatives low, and a spam filter to keep false positives low.
Multi-Class Confusion Matrices#
With N classes the matrix is N × N. In the orientation used by scikit-learn's confusion_matrix, each row is a true class and each column a predicted class. Reading along a row shows where that class's examples went, so the diagonal cell over the row total is the class's recall. Reading down a column shows what the model's predictions of that class really were, so the diagonal cell over the column total is the class's precision. Some tools draw the matrix transposed, so the axis labels decide how to read a chart.
from sklearn.metrics import confusion_matrix
# True and predicted labels for 10 images
y_true = ["cat", "cat", "cat", "dog", "dog", "dog", "dog", "fox", "fox", "fox"]
y_pred = ["cat", "cat", "dog", "dog", "dog", "dog", "cat", "fox", "dog", "fox"]
# Rows are true classes and columns are predicted classes, in this label order
labels = ["cat", "dog", "fox"]
matrix = confusion_matrix(y_true, y_pred, labels=labels)
print(matrix)The printed rows for cat, dog, and fox are [2 1 0], [1 3 0], and [0 1 2]. The diagonal holds 7 of the 10 images, so accuracy is 0.7. The dog column collects one cat and one fox, which puts dog precision at 3 / 5 = 0.6, and the dog row loses one image to cat, which puts dog recall at 3 / 4 = 0.75. A normalized matrix divides each cell by its true-class total, so the diagonal shows per-class recall and classes of very different sizes become comparable.
Confusion Matrices for Object Detection#
Detection adds a background class, because a detector can report a box where nothing is or miss an object entirely. Predictions are first matched to labels by intersection over union (IoU), then counted: matched pairs land in the class cells, unmatched predictions count as false positives against background, and unmatched labels count as false negatives predicted as background. The background-to-background cell stays empty because empty image regions cannot be counted, so a detection matrix has no true negatives. YOLO26 validation builds this matrix with one extra row and column for background, matching predictions to labels at an IoU above 0.45, and saves it as confusion_matrix.png with predicted classes on the vertical axis and true classes on the horizontal axis.
from ultralytics import YOLO
# Load a pretrained YOLO26 nano detector
model = YOLO("yolo26n.pt")
# Validation builds the confusion matrix and saves it as confusion_matrix.png
metrics = model.val(data="coco8.yaml")
matrix = metrics.confusion_matrix.matrix # rows: predicted class, columns: true class
# 80 COCO classes plus one background row and column
print(matrix.shape)
# Class 0 is "person": correct detections and people the model missed
print(f"Person TP: {matrix[0, 0]:.0f}, missed: {matrix[-1, 0]:.0f}")The shape is (81, 81), and the last row counts labeled people that no prediction matched.
Confusion Matrix vs. Related Tools#
- ROC curve: one point per decision threshold, each point summarizing that threshold's confusion matrix as a true positive rate and a false positive rate.
- Mean average precision (mAP): the main detection score, built from the same TP and FP decisions across all confidence levels, without showing which classes are confused.
- Accuracy: the matrix compressed to one number, the diagonal over the total. On a dataset that is 95% negative, a model that always predicts "negative" scores 95% accuracy while its matrix shows zero true positives.










