¿Cómo puedo interpretar la matriz de confusión de Sklearn?


24

Estoy usando la matriz de confusión para verificar el rendimiento de mi clasificador.

Estoy usando Scikit-Learn, estoy un poco confundido. ¿Cómo puedo interpretar el 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]])

¿Cómo puedo tomar la decisión de si estos valores pronosticados son buenos o no?


1
Inicialmente olvídate de sklearn, que es un arenque rojo. La fuente de su malentendido parece más fundamental. Echa un vistazo aquí: en.wikipedia.org/wiki/Confusion_matrix . Concéntrese en la narrativa del ejemplo 3 * 3 en la página de wikipedia. Lo más probable es que aborde cualquiera que sea su confusión.
Zhubarb

Respuestas:


47

La matriz de confusión es una forma de tabular el número de clasificaciones erróneas, es decir, el número de clases predichas que terminaron en un contenedor de clasificación incorrecto basado en las clases verdaderas.

Si bien sklearn.metrics.confusion_matrix proporciona una matriz numérica, me resulta más útil generar un 'informe' usando lo siguiente:

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)

lo que resulta en:

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

Esto nos permite ver que:

  1. Los elementos diagonales muestran el número de clasificaciones correctas para cada clase: 3, 1 y 3 para las clases 0, 1 y 2.
  2. Los elementos fuera de la diagonal proporcionan las clasificaciones erróneas: por ejemplo, 2 de la clase 2 se clasificaron erróneamente como 0, ninguno de la clase 0 se clasificó erróneamente como 2, etc.
  3. El número total de clasificaciones para cada clase en ambos y_truey y_pred, de los subtotales "Todos"

Este método también funciona para etiquetas de texto, y para una gran cantidad de muestras en el conjunto de datos se puede ampliar para proporcionar informes porcentuales.

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

La salida entonces es:

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

donde los números ahora representan el porcentaje (en lugar del número de casos) de los resultados que se clasificaron.

Aunque tenga en cuenta que la sklearn.metrics.confusion_matrixsalida se puede visualizar directamente usando:

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

44
¡Bienvenido a nuestro sitio! Aprecio la atención y la calidad que ha puesto en su primera respuesta aquí.
whuber

1
El primer ejemplo ya no funciona, al menos a partir de pandas-0.13.1. Acabo de actualizar a pandas-0.16.0, y todavía recibo el mismo error:AssertionError: arrays and names must have the same length
chbrown

1
@chbrown: parece que algo cambió en los pandas que necesitan sentarse para ser una matriz o una serie. He actualizado el código de ejemplo para usar y_pred = pd.Series(...). Esto debería funcionar ahora.
achennu

5

En el eje y, la matriz de confusión tiene los valores reales, y en el eje x los valores dados por el predictor. Por lo tanto, los recuentos en la diagonal son el número de predicciones correctas. Y los elementos de la diagonal son predicciones incorrectas.

En tu 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

Es un poco confuso (Dijiste que "el número uno 1 se predijo como 2", mientras que en diagonal es 0), tengo una matriz del elemento 50K, es un poco difícil proyectar todos los valores. ¿Hay alguna métrica para darme estos resultados directamente? (Quiero decir, si obtengo una buena matriz de confusión o no).
user3378649

1
Podrías mirar los elementos en diagonal, esas son tus predicciones correctas, los elementos fuera de la diagonal son predicciones incorrectas. Eso es un comienzo.
Akavall

Obtuve dos resultados diferentes. En el objetivo, tenemos dos etiquetas '0' o '1'. ¿Puede ayudarnos a dar una pista sobre cómo interpretar esos resultados? - confusion_matrix: [[0 85723] [0 77]] - confusion_matrix: [[85648 75] [75 2]]
usuario3378649

1

Me gustaría especificar gráficamente la necesidad de entender esto. Es una matriz simple que necesita ser bien entendida antes de llegar a conclusiones. Así que aquí hay una versión explicable simplificada de las respuestas anteriores.

        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

44
¿Podría editar esto para decir cómo cree que va más allá de las respuestas ya dadas?
mdewey

1
¡Oye! Me acabo de referir a la respuesta de Akavall. Él ha mencionado el pensamiento involucrado. Acabo de explicar su respuesta, que tiende a ser la correcta, probablemente de una mejor manera.
Pranzell

@Pranzell ¿Podría compartir su código para dibujar una tabla tan hermosa basada en texto?
Fu DL
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.