I was debating with myself whether this was too basic to bring up but after writing it, I’m glad I did.
Referencing scikit-learn’s confusion matrix documentation, it’s not immediately apparent what convention the axes follow. When the confusion_matrix function is called,
from sklearn.metrics import confusion_matrix
y_true = [0, 0, 0, 1, 1, 1, 1, 1, 1, 1]
y_pred = [0, 1, 1, 0, 0, 0, 1, 1, 1, 1]
cm_2 = confusion_matrix(y_true, y_pred)
cm_2
we get the following output:

So which value corresponds to True Negative, True Positive, False Negative, False Positive?
A quick Google search on “confusion matrix” shows:

And clicking through, we see different illustrations of it.
https://www.sciencedirect.com/science/article/abs/pii/B9780128240540000265

https://www.sciencedirect.com/science/article/abs/pii/B9780323911979000138

https://www.sciencedirect.com/science/article/abs/pii/B9780128183663000058

So which is it for the scikit-learn confusion_matrix function output?




Let’s look at it again:
from sklearn.metrics import confusion_matrix
y_true = [0, 0, 0, 1, 1, 1, 1, 1, 1, 1]
y_pred = [0, 1, 1, 0, 0, 0, 1, 1, 1, 1]
cm_2 = confusion_matrix(y_true, y_pred)
cm_2

We can see that the terms in the predicted list y_pred
are:
[TN, FP, FP, FN, FN, FN, TP, TP, TP, TP]
And the count of the terms are:
Actual_0_Predicted_0 (True Negative) = 1
Actual_0_Predicted_1 (False Positive) = 2
Actual_1_Predicted_0 (False Negative) = 3
Actual_1_Predicted_1 (True Positive) = 4
Matching the confusion_matrix output and the count of the terms, we can see that the matrix is arranged as such:


We’ll plot it with a seaborn heatmap and label the axes appropriately:
import seaborn as sns
sns.heatmap(cm_2, annot=True, cmap='Blues').set(xlabel='Predicted Class', ylabel='Actual Class')

Addendum: If you simply can’t commit to memory the confusion_matrix function’s output order, one hacky way to check what you need is by assigning them like so:
cm_2 = confusion_matrix(y_true, y_pred)
tn = cm_2[0][0]
fp = cm_2[0][1]
fn = cm_2[1][0]
tp = cm_2[1][1]
This is easy to remember as:
True Negative = Actual_0_Predicted_0
False Positive = Actual_0_Predicted_1
False Negative = Actual_1_Predicted_0
True Positive = Actual_1_Predicted_1
I don’t see it written anywhere but it’s quite possible the scikit-learn developers intentionally chose their confusion matrix array/axis arrangement so as to match the indexing of a 2D array, which is pretty nifty.
Now that we’re clear about it, there’s an error in this illustration, can you see what it is and how to correct it?
https://datagy.io/python-confusion-matrix/

(correction needed = swap the axes)
You can play around with the following Google Colab Notebook to help build some intuition. Scroll down for a multi-class confusion matrix.
Discussion
Comments are closed.