матриця змішання ділянок sklearn із мітками


85

Я хочу побудувати матрицю плутанини для візуалізації роботи класифікатора, але вона відображає лише номери етикеток, а не самі мітки:

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('Confusion matrix of the classifier')
pl.colorbar()
pl.show()

Як я можу додати мітки (охорона здоров'я, бізнес .. тощо) до матриці плутанини?

Відповіді:


66

Як вказувалося в цьому питанні , ви повинні «відкрити» художника API нижчого рівня , шляхом збереження фігури і об'єкти осі передається функціями Matplotlib ви називаєте (по fig, axі caxзмінні нижче). Потім ви можете замінити типові позначки осі x та y за допомогою 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('Confusion matrix of the classifier')
fig.colorbar(cax)
ax.set_xticklabels([''] + labels)
ax.set_yticklabels([''] + labels)
plt.xlabel('Predicted')
plt.ylabel('True')
plt.show()

Зверніть увагу, що я передав labelsсписок confusion_matrixфункції, щоб переконатися, що вона правильно відсортована, збігаючись з галочками.

З цього випливає наступний малюнок:

введіть тут опис зображення


3
Якщо у вас більше кількох категорій, Matplotlib вирішує неправильно позначити осі - вам потрібно змусити його позначити кожну клітинку. from matplotlib.ticker import MultipleLocator; ax.xaxis.set_major_locator(MultipleLocator(1)); ax.yaxis.set_major_locator(MultipleLocator(1))
rescdsk

Будучи новим, не могли б ви сказати мені, чи розмір 3 коробок означає рівень точності?
Борис

як відобразити на них цифри? оскільки кольори можуть не багато чого передавати у всіх випадках
kRazzy R 01.03.18

Привіт ... @ metakermit. Не могли б ви сказати, як показати цифри всередині кольорової фігури?
Хумаун Рашид Наян,

70

ОНОВЛЕННЯ:

У scikit-learn 0.22 є нова функція для безпосереднього побудови матриці плутанини.

Дивіться документацію: sklearn.metrics.plot_confusion_matrix


СТАРИЙ ВІДПОВІДЬ:

Думаю, варто згадати про використання seaborn.heatmapтут.

import seaborn as sns
import matplotlib.pyplot as plt     

ax= plt.subplot()
sns.heatmap(cm, annot=True, ax = ax); #annot=True to annotate cells

# labels, title and ticks
ax.set_xlabel('Predicted labels');ax.set_ylabel('True labels'); 
ax.set_title('Confusion Matrix'); 
ax.xaxis.set_ticklabels(['business', 'health']); ax.yaxis.set_ticklabels(['health', 'business']);

введіть тут опис зображення


32
Пропозиція: перейдіть fmt='g'на heatmapдзвінок, щоб номери не переходили до наукових позначень.
polm23,

5
Пропозиція: перейти cmap='Greens'до heatmapдзвінка, щоб мати інтуїтивне значення кольору.
EliadL

Як бути впевненим, що ви не змішуєте ярлики?
Революція для Моніки

@RevolucionforMonica Коли ви отримуєте confusion_matrix, мітки галочок осі X становлять 1, 0, а мітки галочок осі Y - 0, 1 (у порядку збільшення значень осі). Якщо класифікатор є clf, ви можете отримати порядок класів за clf.classes_, який ["health", "business"]у цьому випадку повинен відповідати . (Передбачається, що businessце позитивний клас).
akilat90

29

Я знайшов функцію, яка може побудувати матрицю плутанини, яка генерується з sklearn.

import numpy as np


def plot_confusion_matrix(cm,
                          target_names,
                          title='Confusion matrix',
                          cmap=None,
                          normalize=True):
    """
    given a sklearn confusion matrix (cm), make a nice plot

    Arguments
    ---------
    cm:           confusion matrix from sklearn.metrics.confusion_matrix

    target_names: given classification classes such as [0, 1, 2]
                  the class names, for example: ['high', 'medium', 'low']

    title:        the text to display at the top of the matrix

    cmap:         the gradient of the values displayed from matplotlib.pyplot.cm
                  see http://matplotlib.org/examples/color/colormaps_reference.html
                  plt.get_cmap('jet') or plt.cm.Blues

    normalize:    If False, plot the raw numbers
                  If True, plot the proportions

    Usage
    -----
    plot_confusion_matrix(cm           = cm,                  # confusion matrix created by
                                                              # sklearn.metrics.confusion_matrix
                          normalize    = True,                # show proportions
                          target_names = y_labels_vals,       # list of names of the classes
                          title        = best_estimator_name) # title of graph

    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('True label')
    plt.xlabel('Predicted label\naccuracy={:0.4f}; misclass={:0.4f}'.format(accuracy, misclass))
    plt.show()

Це буде виглядати так введіть тут опис зображення


23

Вас може зацікавити https://github.com/pandas-ml/pandas-ml/

який реалізує реалізацію Python Pandas Confusion Matrix.

Деякі особливості:

  • матриця плутанини сюжетів
  • графік нормалізованої матриці плутанини
  • статистика класу
  • загальна статистика

Ось приклад:

In [1]: from pandas_ml import ConfusionMatrix
In [2]: import matplotlib.pyplot as plt

In [3]: y_test = ['business', 'business', 'business', 'business', 'business',
        'business', 'business', 'business', 'business', 'business',
        'business', 'business', 'business', 'business', 'business',
        'business', 'business', 'business', 'business', 'business']

In [4]: y_pred = ['health', 'business', 'business', 'business', 'business',
       'business', 'health', 'health', 'business', 'business', 'business',
       'business', 'business', 'business', 'business', 'business',
       'health', 'health', 'business', 'health']

In [5]: cm = ConfusionMatrix(y_test, y_pred)

In [6]: cm
Out[6]:
Predicted  business  health  __all__
Actual
business         14       6       20
health            0       0        0
__all__          14       6       20

In [7]: cm.plot()
Out[7]: <matplotlib.axes._subplots.AxesSubplot at 0x1093cf9b0>

In [8]: plt.show()

Матриця плутанини графіків

In [9]: cm.print_stats()
Confusion Matrix:

Predicted  business  health  __all__
Actual
business         14       6       20
health            0       0        0
__all__          14       6       20


Overall Statistics:

Accuracy: 0.7
95% CI: (0.45721081772371086, 0.88106840959427235)
No Information Rate: ToDo
P-Value [Acc > NIR]: 0.608009812201
Kappa: 0.0
Mcnemar's Test P-Value: ToDo


Class Statistics:

Classes                                 business health
Population                                    20     20
P: Condition positive                         20      0
N: Condition negative                          0     20
Test outcome positive                         14      6
Test outcome negative                          6     14
TP: True Positive                             14      0
TN: True Negative                              0     14
FP: False Positive                             0      6
FN: False Negative                             6      0
TPR: (Sensitivity, hit rate, recall)         0.7    NaN
TNR=SPC: (Specificity)                       NaN    0.7
PPV: Pos Pred Value (Precision)                1      0
NPV: Neg Pred Value                            0      1
FPR: False-out                               NaN    0.3
FDR: False Discovery Rate                      0      1
FNR: Miss Rate                               0.3    NaN
ACC: Accuracy                                0.7    0.7
F1 score                               0.8235294      0
MCC: Matthews correlation coefficient        NaN    NaN
Informedness                                 NaN    NaN
Markedness                                     0      0
Prevalence                                     1      0
LR+: Positive likelihood ratio               NaN    NaN
LR-: Negative likelihood ratio               NaN    NaN
DOR: Diagnostic odds ratio                   NaN    NaN
FOR: False omission rate                       1      0

Що, як ти змусив це працювати? З останньою програмою pandas_ml він дає мені порожню матрицю плутанини (усі 0), а мітки мають значення True / False замість бізнесу та здоров'я.
іншому випадку

те саме, він пустий
Елхам

1
Я отримую AttributeError: модуль 'sklearn.metrics' не має атрибута 'jaccard_s similarity_score' у scikit-learn версії 0.23.1 та pandas-ml версії 0.6.1. Я спробував і інші версії, не маючи удачі.
petra

18
from 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)

from 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("Accuracy: %.3f%%" % (result*100.0))
y_pred = model.predict(X_test)
print("F1 Score: ", f1_score(y_test, y_pred, average="macro"))
print("Precision Score: ", precision_score(y_test, y_pred, average="macro"))
print("Recall Score: ", 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
from sklearn.metrics import confusion_matrix

def cm_analysis(y_true, y_pred, labels, ymap=None, figsize=(10,10)):
    """
    Generate matrix plot of confusion matrix with pretty annotations.
    The plot image is saved to disk.
    args: 
      y_true:    true label of the data, with shape (nsamples,)
      y_pred:    prediction of the data, with shape (nsamples,)
      filename:  filename of figure file to save
      labels:    string array, name the order of class labels in the confusion matrix.
                 use `clf.classes_` if using scikit-learn models.
                 with shape (nclass,).
      ymap:      dict: any -> string, length == nclass.
                 if not None, map the labels & ys to more understandable strings.
                 Caution: original y_true, y_pred and labels must align.
      figsize:   the size of the figure plotted.
    """
    if ymap is not None:
        y_pred = [ymap[yi] for yi in y_pred]
        y_true = [ymap[yi] for yi in y_true]
        labels = [ymap[yi] for yi in labels]
    cm = confusion_matrix(y_true, y_pred, labels=labels)
    cm_sum = np.sum(cm, axis=1, keepdims=True)
    cm_perc = cm / cm_sum.astype(float) * 100
    annot = np.empty_like(cm).astype(str)
    nrows, ncols = cm.shape
    for i in range(nrows):
        for j in range(ncols):
            c = cm[i, j]
            p = cm_perc[i, j]
            if i == j:
                s = cm_sum[i]
                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)
    cm = pd.DataFrame(cm, index=labels, columns=labels)
    cm.index.name = 'Actual'
    cm.columns.name = 'Predicted'
    fig, ax = plt.subplots(figsize=figsize)
    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))

введіть тут опис зображення

за допомогою https://gist.github.com/hitvoice/36cf44689065ca9b927431546381a3f7

Зверніть увагу, що якщо ви використовуєте, rocket_rце змінить кольори, і це якось виглядає більш природно і краще, наприклад, нижче: введіть тут опис зображення


Дякую, але який rocket_rваріант ви згадали?
Hamman Samuel

у функції sns.heatmap()передайте аргумент cmap='rocket_r'для кольору, зворотного до шкали
Sai Prabhanjan Reddy

10
    from sklearn.metrics import confusion_matrix
    import seaborn as sns
    import matplotlib.pyplot as plt
    model.fit(train_x, train_y,validation_split = 0.1, epochs=50, batch_size=4)
    y_pred=model.predict(test_x,batch_size=15)
    cm =confusion_matrix(test_y.argmax(axis=1), y_pred.argmax(axis=1))  
    index = ['neutral','happy','sad']  
    columns = ['neutral','happy','sad']  
    cm_df = pd.DataFrame(cm,columns,index)                      
    plt.figure(figsize=(10,6))  
    sns.heatmap(cm_df, annot=True)

Матриця плутанини


8

Щоб додати до оновлення @ akilat90 про sklearn.metrics.plot_confusion_matrix:

Ви можете використовувати ConfusionMatrixDisplayклас sklearn.metricsбезпосередньо і обійти необхідність передавати класифікатор plot_confusion_matrix. Він також маєdisplay_labels аргумент, який дозволяє вказати мітки, що відображаються на графіку, як потрібно.

Конструктор for ConfusionMatrixDisplayне надає способу зробити додаткові налаштування сюжету, але ви можете отримати доступ до осей matplotlib obect через ax_атрибут після виклику його plot()методу. Я додав другий приклад, що це показує.

Мені було прикро, коли потрібно повторно запускати класифікатор для великого обсягу даних, лише для створення сюжету plot_confusion_matrix . Я виробляю інші змови за прогнозованими даними, тому я не хочу витрачати свій час на повторне прогнозування кожного разу. Це також було простим рішенням цієї проблеми.

Приклад:

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()

матриця плутанини приклад 1

Приклад використання ax_:

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

приклад матриці плутанини


1
Це чудово - дякую! Запитання: Чи можете ви налаштувати значення "Справжня мітка" та "Передбачена мітка" для міток осей?
кайдін

1
Раніше я цього не розумів, але ви можете отримати доступ до об’єкта matplotlib axes через cmd.ax_, що дозволяє багато контролювати графік. Для того, щоб налаштувати мітки осі використовувати що - щось на зразок цього: cmd.ax_.set(xlabel='foo', ylabel='bar'). Я оновлю свою відповідь.
themaninthewoods

Дуже дякую! Але схоже на cmd.ax_.setвідключення display_labels=['business','health']?
caydin

Також я отримую AttributeError: 'ConfusionMatrixDisplay' object has no attribute 'ax_' .
caydin

1
Ах, ти маєш рацію! Дякуємо, що вказали на ці речі. У своєму захваті від пошуку рішення я зробив кілька помилок під час оновлення. Будь ласка, перегляньте останню версію, вона повинна запрацювати зараз.
themaninthewoods
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.