Como interpretar a matriz de confusão do Sklearn

24

Estou usando a matriz de confusão para verificar o desempenho do meu classificador.

Estou usando o Scikit-Learn, estou um pouco confuso. Como posso interpretar o resultado de

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

Como posso decidir se esses valores previstos são bons ou não.

user3378649
fonte
1
Inicialmente esqueça o sklearn, isso é um arenque vermelho. A fonte do seu mal-entendido parece mais fundamental. Dê uma olhada aqui: en.wikipedia.org/wiki/Confusion_matrix . Concentre-se na narrativa do exemplo 3 * 3 na página da Wikipedia. Isso provavelmente irá resolver qualquer que seja sua confusão.
Zhubarb
Uma discussão relevante: stats.stackexchange.com/a/340079/121522
mkt - Restabelece Monica

Respostas:

47

A matriz de confusão é uma maneira de tabular o número de erros de classificação, ou seja, o número de classes previstas que terminaram em uma posição errada na classificação com base nas classes verdadeiras.

Enquanto sklearn.metrics.confusion_matrix fornece uma matriz numérica, acho mais útil gerar um 'relatório' usando o seguinte:

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)

o que resulta em:

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

Isso nos permite ver que:

  1. Os elementos diagonais mostram o número de classificações corretas para cada classe: 3, 1 e 3 para as classes 0, 1 e 2.
  2. Os elementos fora da diagonal fornecem as classificações incorretas: por exemplo, 2 da classe 2 foram classificadas incorretamente como 0, nenhuma da classe 0 foi classificada incorretamente como 2, etc.
  3. O número total de classificações para cada classe nos dois y_truee y_pred, dos subtotais "Todos"

Esse método também funciona para rótulos de texto e, para um grande número de amostras no conjunto de dados, pode ser estendido para fornecer relatórios de porcentagem.

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

A saída é então:

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

onde os números agora representam a porcentagem (e não o número de casos) dos resultados que foram classificados.

Embora observe que a sklearn.metrics.confusion_matrixsaída pode ser visualizada diretamente usando:

import matplotlib.pyplot as plt
conf = sklearn.metrics.confusion_matrix(y_true, y_pred)
plt.imshow(conf, cmap='binary', interpolation='None')
plt.show()
achennu
fonte
4
Bem vindo ao nosso site! Agradeço o cuidado e a qualidade que você colocou em sua primeira resposta aqui.
whuber
1
O primeiro exemplo não funciona mais, pelo menos a partir dos pandas-0.13.1. Acabei de atualizar para o pandas-0.16.0 e continuo com o mesmo erro:AssertionError: arrays and names must have the same length
chbrown 17/04/2015
1
@chbrown: parece que algo mudou nos pandas que precisam sentar para serem uma matriz ou uma série. Atualizei o código de exemplo para usar y_pred = pd.Series(...). Isso deve funcionar agora.
achennu
5

No eixo y, a matriz de confusão possui os valores reais e, no eixo x, os valores fornecidos pelo preditor. Portanto, as contagens na diagonal são o número de previsões corretas. E os elementos da diagonal são previsões incorretas.

No seu 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
Akavall
fonte
É um pouco confuso (você disse que "o primeiro número 1 foi previsto como 2" - enquanto a diagonal é 0), eu tenho uma matriz de elemento de 50K, é um pouco difícil projetar todos os valores. Existe alguma métrica para fornecer esses resultados diretamente? (Quero dizer, se estou recebendo uma boa matriz de confusão ou não).
user3378649
1
Você pode olhar para os elementos na diagonal, essas são suas previsões corretas, os elementos fora da diagonal são previsões erradas. Isso é um começo.
precisa saber é o seguinte
Eu tenho dois resultados diferentes. No destino, temos dois rótulos '0' ou '1'. Você pode ajudar a dar uma dica de como interpretar esses resultados. - confusion_matrix: [[0 85723] [0 77]] - confusion_matrix: [[85648 75] [75 2]]
user3378649
1

Gostaria de especificar graficamente a necessidade de entender isso. É uma matriz simples que precisa ser bem compreendida antes de se chegar a conclusões. Então, aqui está uma versão explicável simplificada das respostas acima.

        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
Pranzell
fonte
4
Você poderia editar isso para dizer como acha que vai além das respostas já dadas?
Mdewey
1
Ei! Acabei de me referir à resposta de Akavall. Ele mencionou o pensamento envolvido. Acabei de explicar sua resposta, que tende a ser a correta, de uma maneira melhor, presumivelmente.
Pranzell
@Pranzell Você poderia compartilhar seu código para desenhar uma tabela baseada em texto tão bonita?
fu DL