How to Compute a Confusion Matrix in Python
Compute a multi-class confusion matrix from true and predicted labels using pure Python dictionaries and nested lists, then format it for readable output.
Python code
29 linesfrom collections import defaultdict
def compute_confusion_matrix(y_true, y_pred, labels):
"""Compute confusion matrix using Python dicts and nested lists."""
label_index = {label: i for i, label in enumerate(labels)}
matrix = [[0] * len(labels) for _ in range(len(labels))]
for true, pred in zip(y_true, y_pred):
i = label_index[true]
j = label_index[pred]
matrix[i][j] += 1
return matrix
def format_confusion_matrix(matrix, labels):
"""Return a formatted string representation of the confusion matrix."""
header = " " + " ".join(f"{label:>5}" for label in labels)
lines = [header]
for i, label in enumerate(labels):
row = f"{label:>5} " + " ".join(f"{val:>5}" for val in matrix[i])
lines.append(row)
return "\n".join(lines)
if __name__ == "__main__":
y_true = ["cat", "dog", "cat", "cat", "dog", "bird", "bird", "dog"]
y_pred = ["cat", "dog", "dog", "cat", "bird", "cat", "bird", "dog"]
labels = ["cat", "dog", "bird"]
cm = compute_confusion_matrix(y_true, y_pred, labels)
print(format_confusion_matrix(cm, labels))
Output
cat dog bird
cat 2 1 0
dog 1 2 1
bird 1 0 1
How it works
This implementation builds a mapping from each label to its row/column index in the matrix. For every pair of true and predicted labels, it increments the corresponding cell, counting how many times a true class was predicted as another class. Using nested lists for the matrix keeps the code dependency-free and straightforward for small datasets. The formatting function aligns columns with fixed-width padding, making the result easy to read and share.
Common mistakes
- Assuming labels are sorted or unique in the given order; always pass an explicit labels list.
- Using y_true and y_pred lists of different lengths, causing zip to silently truncate.
- Forgetting that label_index lookup raises KeyError for unseen labels; consider using .get() with a default.
- Using a single flat list instead of nested lists for the matrix, causing index errors.
Variations
- Use numpy arrays and sklearn.metrics.confusion_matrix for a battle-tested version with built-in normalization.
- Return a dictionary of dictionaries (e.g., {true: {pred: count}}) for easier access in code.
Real-world use cases
- Evaluating a classification model's per-class performance during model validation or feature selection.
- Debugging imbalanced datasets by spotting classes that the model frequently confuses with others.
- Building a custom monitoring script that flags when confusion patterns change across model retraining.
Sponsored
More from ML engineering pipelines
- Bayesian Optimization in Python: A Simplified Mock Implementation medium
- Build a Data Helper Class in Python for ML Pipelines easy
- Build a Mock Random Forest Classifier in Python easy
- Champion Challenger Deployment Mock in Python easy
- Compare Model A vs Model B Metrics in Python easy
- Create a Minimal Great Expectations Suite Mock in Python easy
Keep learning
Related tutorials and quizzes for this topic.