Come posso interpretare la matrice di confusione di Sklearn


24

Sto usando la matrice di confusione per verificare le prestazioni del mio classificatore.

Sto usando Scikit-Learn, sono un po 'confuso. Come posso interpretare il risultato da

from sklearn.metrics import confusion_matrix
>>> y_true = [2, 0, 2, 2, 0, 1]
>>> y_pred = [0, 0, 2, 2, 0, 2]
>>> confusion_matrix(y_true, y_pred)
array([[2, 0, 0],
       [0, 0, 1],
       [1, 0, 2]])

Come posso prendere la decisione se questi valori previsti sono buoni o no.


1
Inizialmente dimentica sklearn, è un'aringa rossa. La fonte del tuo malinteso sembra più fondamentale. Dai un'occhiata qui: en.wikipedia.org/wiki/Confusion_matrix . Concentrati sulla narrazione dell'esempio 3 * 3 sulla pagina di Wikipedia. Molto probabilmente questo affronterà qualunque sia la tua confusione.
Zhubarb,

Una discussione pertinente: stats.stackexchange.com/a/340079/121522
mkt -

Risposte:


47

La matrice di confusione è un modo per tabulare il numero di classificazioni errate, cioè il numero di classi previste che sono finite in un contenitore di classificazione errato basato sulle classi vere.

Mentre sklearn.metrics.confusion_matrix fornisce una matrice numerica, trovo più utile generare un "rapporto" usando quanto segue:

import pandas as pd
y_true = pd.Series([2, 0, 2, 2, 0, 1, 1, 2, 2, 0, 1, 2])
y_pred = pd.Series([0, 0, 2, 1, 0, 2, 1, 0, 2, 0, 2, 2])

pd.crosstab(y_true, y_pred, rownames=['True'], colnames=['Predicted'], margins=True)

che si traduce in:

Predicted  0  1  2  All
True                   
0          3  0  0    3
1          0  1  2    3
2          2  1  3    6
All        5  2  5   12

Questo ci consente di vedere che:

  1. Gli elementi diagonali mostrano il numero di classificazioni corrette per ogni classe: 3, 1 e 3 per le classi 0, 1 e 2.
  2. Gli elementi fuori diagonale forniscono le classificazioni errate: ad esempio, 2 della classe 2 sono stati classificati erroneamente come 0, nessuno della classe 0 è stato classificato erroneamente come 2, ecc.
  3. Il numero totale di classificazioni per ciascuna classe in entrambi y_truee y_pred, dai totali parziali "Tutti"

Questo metodo funziona anche per le etichette di testo e per un gran numero di campioni nel set di dati può essere esteso per fornire rapporti percentuali.

import numpy as np
import pandas as pd

# create some data
lookup = {0: 'biscuit', 1:'candy', 2:'chocolate', 3:'praline', 4:'cake', 5:'shortbread'}
y_true = pd.Series([lookup[_] for _ in np.random.random_integers(0, 5, size=100)])
y_pred = pd.Series([lookup[_] for _ in np.random.random_integers(0, 5, size=100)])

pd.crosstab(y_true, y_pred, rownames=['True'], colnames=['Predicted']).apply(lambda r: 100.0 * r/r.sum())

L'output quindi è:

Predicted     biscuit  cake      candy  chocolate    praline  shortbread
True                                                                    
biscuit     23.529412    10  23.076923  13.333333  15.384615    9.090909
cake        17.647059    20   0.000000  26.666667  15.384615   18.181818
candy       11.764706    20  23.076923  13.333333  23.076923   31.818182
chocolate   11.764706     5  15.384615   6.666667  15.384615   13.636364
praline     17.647059    10  30.769231  20.000000   0.000000   13.636364
shortbread  17.647059    35   7.692308  20.000000  30.769231   13.636364

dove i numeri ora rappresentano la percentuale (anziché il numero di casi) dei risultati che sono stati classificati.

Sebbene si noti che l' sklearn.metrics.confusion_matrixoutput può essere visualizzato direttamente usando:

import matplotlib.pyplot as plt
conf = sklearn.metrics.confusion_matrix(y_true, y_pred)
plt.imshow(conf, cmap='binary', interpolation='None')
plt.show()

4
Benvenuti nel nostro sito! Apprezzo la cura e la qualità che hai messo nella tua prima risposta qui.
whuber

1
Il primo esempio non funziona più, almeno a partire da panda-0.13.1. Ho appena effettuato l'aggiornamento a Panda-0.16.0 e ho ancora lo stesso errore:AssertionError: arrays and names must have the same length
chbrown

1
@chbrown: sembra che qualcosa sia cambiato nei panda che hanno bisogno di sedersi per essere un array o una serie. Ho aggiornato il codice di esempio da utilizzare y_pred = pd.Series(...). Questo dovrebbe funzionare ora.
Achennu,

5

Sulla matrice di confusione dell'asse y ha i valori effettivi e sull'asse x i valori forniti dal predittore. Pertanto, i conteggi sulla diagonale sono il numero di previsioni corrette. E gli elementi della diagonale sono previsioni errate.

Nel tuo caso:

>>> confusion_matrix(y_true, y_pred)
    array([[2, 0, 0],  # two zeros were predicted as zeros
           [0, 0, 1],  # one 1 was predicted as 2
           [1, 0, 2]]) # two 2s were predicted as 2, and one 2 was 0

È un po 'confuso (hai detto che "# 1 era previsto come 2" - mentre in diagonale è 0), ho una matrice di 50K elementi, è un po' difficile proiettare tutti i valori. C'è qualche metrica per darmi direttamente questi risultati? (Voglio dire se sto ottenendo una buona matrice di confusione o no).
user3378649

1
Potresti guardare gli elementi sulla diagonale, quelli sono i tuoi pronostici corretti, gli elementi fuori diagonale sono i pronostici sbagliati. Questo è un inizio.
Akavall,

Ho ottenuto due risultati diversi. Nel target, abbiamo due etichette '0' o '1', puoi aiutarci a dare un suggerimento su come interpretare quei risultati. - confusion_matrix: [[0 85723] [0 77]] - confusion_matrix: [[85648 75] [75 2]]
user3378649

1

Vorrei specificare graficamente la necessità di capirlo. È una matrice semplice che deve essere ben compresa prima di arrivare alle conclusioni. Quindi, ecco una versione spiegabile semplificata delle risposte di cui sopra.

        0  1  2   <- Predicted
     0 [2, 0, 0]  
TRUE 1 [0, 0, 1]  
     2 [1, 0, 2] 

# At 0,0: True value was 0, Predicted value was 0, - 2 times predicted
# At 1,1: True value was 1, Predicted value was 1, - 0 times predicted
# At 2,2: True value was 2, Predicted value was 2, - 2 times predicted
# At 1,2: True value was 1, Predicted value was 2, - 1 time predicted
# At 2,0: True value was 2, Predicted value was 0, - 1 time predicted...
...Like that

4
Potresti modificarlo per dire come pensi che vada oltre le risposte già fornite?
mdewey,

1
Hey! Ho appena fatto riferimento alla risposta di Akavall. Ha citato il pensiero coinvolto. Ho appena spiegato la sua risposta, che tende ad essere corretta, presumibilmente in un modo migliore.
Pranzell,

@Pranzell Vuoi condividere il tuo codice per disegnare una tabella così bella basata su testo?
fu DL
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.