Aizzaac
Aizzaac

Reputation: 3318

How to change the ticks in a confusion matrix?

I am working with a confusion matrix (Figure A)

How can I make my ticks to start from 1 to 3 instead of 0 to 2?

I tried adding a +1 in tick_marks. But it does not work (Figure B)

Check my code:

import itertools

cm = confusion_matrix(y_test, y_pred)
np.set_printoptions(precision=2)
print('Confusion matrix, without normalization')
print(cm)
plt.figure()
plot_confusion_matrix(cm)


def plot_confusion_matrix(cm, title='Confusion matrix', cmap=plt.cm.Oranges):
    plt.imshow(cm, interpolation='nearest', cmap=cmap)
    plt.title(title)
    plt.colorbar()
    tick_marks = np.arange(len(iris.target_names)) + 1

    plt.xticks(tick_marks, rotation=45)
    plt.yticks(tick_marks)

    thresh = cm.max() / 2.
    for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
        plt.text(j, i, cm[i, j],
                 horizontalalignment="center",
                 color="white" if cm[i, j] > thresh else "black")

    plt.tight_layout()
    plt.ylabel('True label')
    plt.xlabel('Predicted label')

Figure A:

enter image description here

Figure B

enter image description here

Upvotes: 0

Views: 6516

Answers (2)

ki-ang
ki-ang

Reputation: 11

I faced a similar problem: When I wanted to use custom labels for my classes, either the squared boxes went out of bounds or the labels were being offset, as you show here.

If you have multiple labels (>7), then first you need to explicitly set the tick frequency to one using plticker.MultipleLocator. Then you simply set the x and y ticklabels without mentioning the ticks (To not set the xticks and yticks is important. If you do so, the imshow/matshow part gets chopped off at the top.) Add the following lines inside the plot_confusion_matrix function.

import matplotlib.ticker as plticker

fig = plt.figure()
ax = fig.add_subplot(111)
cax = ax.matshow(cm,cmap=cmap)
fig.colorbar(cax)
loc = plticker.MultipleLocator(base=1.0)
ax.xaxis.set_major_locator(loc)
ax.yaxis.set_major_locator(loc)
ax.set_yticklabels(['']+iris.target_names)
ax.set_xticklabels(['']+iris.target_names)

Upvotes: 1

Kennet Celeste
Kennet Celeste

Reputation: 4771

You should get the axis of the plt and change the xtick_labels (if that's what you intend to do):

import itertools
import numpy as np
import matplotlib.pyplot as plt

from sklearn import svm, datasets
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix

# import some data to play with
iris = datasets.load_iris()
X = iris.data
y = iris.target
class_names = iris.target_names

# Split the data into a training set and a test set
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)

# Run classifier, using a model that is too regularized (C too low) to see
# the impact on the results
classifier = svm.SVC(kernel='linear', C=0.01)
y_pred = classifier.fit(X_train, y_train).predict(X_test)


def plot_confusion_matrix(cm, title='Confusion matrix', cmap=plt.cm.Oranges):
    plt.imshow(cm, interpolation='nearest', cmap=cmap)
    plt.title(title)
    plt.colorbar()
    tick_marks = np.arange(len(iris.target_names))
    plt.xticks(tick_marks, rotation=45)
    ax = plt.gca()
    ax.set_xticklabels((ax.get_xticks() +1).astype(str))
    plt.yticks(tick_marks)

    thresh = cm.max() / 2.
    for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
        plt.text(j, i, cm[i, j],
                 horizontalalignment="center",
                 color="white" if cm[i, j] > thresh else "black")

    plt.tight_layout()
    plt.ylabel('True label')
    plt.xlabel('Predicted label')

cm = confusion_matrix(y_test, y_pred)
np.set_printoptions(precision=2)
print('Confusion matrix, without normalization')
print(cm)
fig, ax = plt.subplots()
plot_confusion_matrix(cm)

plt.show()

result:

enter image description here

Upvotes: 5

Related Questions