121 votes

Tracer la matrice de confusion sklearn avec des étiquettes

Je veux tracer une matrice de confusion pour visualiser les performances du classificateur, mais elle n'affiche que les chiffres des étiquettes, pas les étiquettes elles-mêmes :

from sklearn.metrics import confusion_matrix
import pylab as pl
y_test=['business', 'business', 'business', 'business', 'business', 'business', 'business', 'business', 'business', 'business', 'business', 'business', 'business', 'business', 'business', 'business', 'business', 'business', 'business', 'business']

pred=array(['health', 'business', 'business', 'business', 'business',
       'business', 'health', 'health', 'business', 'business', 'business',
       'business', 'business', 'business', 'business', 'business',
       'health', 'health', 'business', 'health'], 
      dtype='|S8')

cm = confusion_matrix(y_test, pred)
pl.matshow(cm)
pl.title('Matrice de confusion du classificateur')
pl.colorbar()
pl.show()

Comment puis-je ajouter les étiquettes (santé, entreprise..etc) à la matrice de confusion ?

101voto

akilat90 Points 1579

MISE À JOUR:

Vérifiez le ConfusionMatrixDisplay


ANCIENNE RÉPONSE:

Je pense qu'il vaut la peine de mentionner l'utilisation de seaborn.heatmap ici.

import seaborn as sns
import matplotlib.pyplot as plt     

ax= plt.subplot()
sns.heatmap(cm, annot=True, fmt='g', ax=ax);  #annot=True to annotate cells, ftm='g' to disable scientific notation

# labels, title and ticks
ax.set_xlabel('Labels prédits');ax.set_ylabel('Labels réels'); 
ax.set_title('Matrice de confusion'); 
ax.xaxis.set_ticklabels(['affaires', 'santé']); ax.yaxis.set_ticklabels(['santé', 'affaires']);

entrez la description de l'image ici

83voto

kermit666 Points 1730

Comme indiqué dans cette question, vous devez "ouvrir" le API artiste de plus bas niveau, en stockant les objets figure et axis transmis par les fonctions matplotlib que vous appelez (les variables fig, ax et cax ci-dessous). Vous pouvez ensuite remplacer les graduations par défaut des axes x et y en utilisant set_xticklabels/set_yticklabels:

from sklearn.metrics import confusion_matrix

labels = ['business', 'health']
cm = confusion_matrix(y_test, pred, labels)
print(cm)
fig = plt.figure()
ax = fig.add_subplot(111)
cax = ax.matshow(cm)
plt.title('Matrice de confusion du classificateur')
fig.colorbar(cax)
ax.set_xticklabels([''] + labels)
ax.set_yticklabels([''] + labels)
plt.xlabel('Prédit')
plt.ylabel('Réel')
plt.show()

Notez que j'ai passé la liste labels à la fonction confusion_matrix pour m'assurer qu'elle soit correctement triée, correspondant aux graduations.

Cela donne la figure suivante:

description de l'image

45voto

Dukamaster Points 31

J'ai trouvé une fonction qui peut tracer la matrice de confusion générée à partir de sklearn.

import numpy as np

def plot_confusion_matrix(cm,
                          target_names,
                          title='Matrice de confusion',
                          cmap=None,
                          normalize=True):
    """
    donné une matrice de confusion sklearn (cm), faire un joli graphique

    Arguments
    ---------
    cm:           matrice de confusion de sklearn.metrics.confusion_matrix

    target_names: classes de classification données telles que [0, 1, 2]
                  les noms des classes, par exemple: ['élevé', 'moyen', 'bas']

    title:        le texte à afficher en haut de la matrice

    cmap:         le dégradé des valeurs affichées de matplotlib.pyplot.cm
                  voir http://matplotlib.org/examples/color/colormaps_reference.html
                  plt.get_cmap('jet') ou plt.cm.Blues

    normalize:    Si False, afficher les chiffres bruts
                  Si True, afficher les proportions

    Utilisation
    -----
    plot_confusion_matrix(cm           = cm,                  # matrice de confusion créée par
                                                              # sklearn.metrics.confusion_matrix
                          normalize    = True,                # montrer les proportions
                          target_names = y_labels_vals,       # liste des noms des classes
                          title        = best_estimator_name) # titre du graphique

    Citiation
    ---------
    http://scikit-learn.org/stable/auto_examples/model_selection/plot_confusion_matrix.html

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

    accuracy = np.trace(cm) / np.sum(cm).astype('float')
    misclass = 1 - accuracy

    if cmap is None:
        cmap = plt.get_cmap('Blues')

    plt.figure(figsize=(8, 6))
    plt.imshow(cm, interpolation='nearest', cmap=cmap)
    plt.title(title)
    plt.colorbar()

    if target_names is not None:
        tick_marks = np.arange(len(target_names))
        plt.xticks(tick_marks, target_names, rotation=45)
        plt.yticks(tick_marks, target_names)

    if normalize:
        cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]

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

    plt.tight_layout()
    plt.ylabel('Étiquette réelle')
    plt.xlabel('Étiquette prédite\nprécision={:0.4f}; erreur={:0.4f}'.format(accuracy, misclass))
    plt.show()

Cela ressemblera à ceci enter image description here

44voto

themaninthewoods Points 490

Pour ajouter à la mise à jour de @akilat90 à propos de sklearn.metrics.plot_confusion_matrix:

Vous pouvez utiliser la classe ConfusionMatrixDisplay directement dans sklearn.metrics et contourner le besoin de passer un classifieur à plot_confusion_matrix. Il possède également l'argument display_labels, qui vous permet de spécifier les étiquettes affichées dans le graphique selon vos besoins.

Le constructeur de ConfusionMatrixDisplay ne fournit pas de moyen de personnaliser davantage le graphique, mais vous pouvez accéder à l'objet des axes matplotlib via l'attribut ax_ après avoir appelé sa méthode plot(). J'ai ajouté un deuxième exemple montrant ceci.

J'ai trouvé irritant de devoir relancer un classifieur sur une grande quantité de données juste pour produire le graphique avec plot_confusion_matrix. Je produis d'autres graphiques à partir des données prédites, donc je ne veux pas gaspiller mon temps à re-prédire à chaque fois. C'était une solution facile à ce problème également.

Exemple :

from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay

cm = confusion_matrix(y_true, y_preds, normalize='all')
cmd = ConfusionMatrixDisplay(cm, display_labels=['business','health'])
cmd.plot()

exemple de matrice de confusion 1

Exemple utilisant ax_:

cm = confusion_matrix(y_true, y_preds, normalize='all')
cmd = ConfusionMatrixDisplay(cm, display_labels=['business','health'])
cmd.plot()
cmd.ax_.set(xlabel='Prédit', ylabel='Vrai')

exemple de matrice de confusion

31voto

Mona Jalal Points 1207
à partir de sklearn import model_selection
test_size = 0,33
seed = 7
X_train, X_test, y_train, y_test = model_selection.train_test_split(feature_vectors, y, test_size=test_size, random_state=seed)

de sklearn.metrics import accuracy_score, f1_score, precision_score, recall_score, classification_report, confusion_matrix

model = LogisticRegression()
model.fit(X_train, y_train)
result = model.score(X_test, y_test)
print("Précision: %.3f%%" % (result*100,0))
y_pred = model.predict(X_test)
print("Score F1: ", f1_score(y_test, y_pred, average="macro"))
print("Score de Précision: ", precision_score(y_test, y_pred, average="macro"))
print("Score de Rappel: ", recall_score(y_test, y_pred, average="macro")) 

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
de sklearn.metrics import confusion_matrix

def cm_analysis(y_true, y_pred, labels, ymap=None, figsize=(10,10)):
    """
    Générer une matrice de confusion avec de jolies annotations.
    args: 
      y_true: vrai label des données, avec une forme (nsamples,)
      y_pred: prédiction des données, avec une forme (nsamples,)
      filename: nom de fichier du fichier image à enregistrer
      labels: tableau de chaînes, nommez l'ordre des étiquettes de classe dans la matrice de confusion.
                 utilisez `clf.classes_` si vous utilisez des modèles scikit-learn.
                 avec une forme (nclasse,).
      ymap: dict: any -> string, longueur == nclasse.
                 si non None, mappez les étiquettes et ys à des chaînes plus compréhensibles.
                 Attention: y_true, y_pred et les étiquettes originales doivent être alignés.
      figsize: la taille de l'image de la figure tracée.
    """
    if ymap is not None:
        # changer les codes ou libellés de catégorie en de nouveaux libellés 
        y_pred = [ymap[yi] pour yi in y_pred]
        y_true = [ymap[yi] pour yi in y_true]
        labels = [ymap[yi] pour yi in labels]
    # calculer une matrice de confusion avec les nouvelles étiquettes
    cm = confusion_matrix(y_true, y_pred, labels=labels)
    # calculer les sommes des lignes (pour calculer % & annotations de tracé)
    cm_sum = np.sum(cm, axis=1, keepdims=True)
    # calculer des proportions
    cm_perc = cm / cm_sum.astype(float) * 100
    # tableau vide pour contenir les annotations pour chaque cellule dans le heatmap
    annot = np.empty_like(cm).astype(str)
    # obtenir les dimensions
    nrows, ncols = cm.shape
    # parcourir les cellules et créer des annotations pour chaque cellule
    for i in range(nrows):
        for j in range(ncols):
            # obtenir le compte pour la cellule
            c = cm[i, j]
            # obtenir le pourcentage pour la cellule
            p = cm_perc[i, j]
            si i == j:
                s = cm_sum[i]
                # convertir la proportion, le décompte et la somme des lignes en une chaîne avec un format joli
                annot[i, j] = '%.1f%%\n%d/%d' % (p, c, s)
            elif c == 0:
                annot[i, j] = ''
            else:
                annot[i, j] = '%.1f%%\n%d' % (p, c)
    # convertir le tableau en un dataframe. Pour tracer par proportion au lieu de nombre, utilisez cm_perc dans le DataFrame au lieu de cm
    cm = pd.DataFrame(cm, index=labels, columns=labels)
    cm.index.name = 'Réel'
    cm.columns.name = 'Prévu'
    # créer une figure vide avec une taille spécifiée
    fig, ax = plt.subplots(figsize=figsize)
    # tracer les données en utilisant le dataframe Pandas. Pour changer la carte de couleur, ajoutez cmap=..., par exemple cmap = 'rocket_r'
    sns.heatmap(cm, annot=annot, fmt='', ax=ax)
    #plt.savefig(filename)
    plt.show()

cm_analysis(y_test,y_pred,model.classes_,ymap=None,figsize=(10,10))

entrer la description de l'image ici

utilisant https://gist.github.com/hitvoice/36cf44689065ca9b927431546381a3f7

Notez que si vous utilisez rocket_r, il inversera les couleurs et d'une certaine manière cela semble plus naturel et meilleur comme ci-dessous: entrer la description de l'image ici

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X