¿Te resulta más fácil leer con fondo crema, un tono de color, más contraste o un texto más grande? Elige tus colores y tu texto una sola vez, para todas las páginas.

Lección gratuita

Juzgar un clasificador con honestidad

Después de esta lección: Puedo juzgar un clasificador con una matriz de confusión, la precisión y la exhaustividad, y no solo con la exactitud.

Lección de 60 min2 comandosLaboratorio JupyterLab de ciencia de datos: pandas, Matplotlib y scikit-learn en el navegador

Noventa y seis por ciento, e inútil

Un filtro de spam se prueba con 1000 mensajes. Acierta 960 veces, así que saca un 96 por ciento. El equipo está contento.

Entonces alguien descubre que el filtro dice «no es spam» a todos los mensajes sin excepción. Cuarenta de los 1000 eran spam. Una sola nota escondió todo el fallo.

Al final de esta lección

Nota

Puedo juzgar un clasificador con una matriz de confusión, la precisión y la exhaustividad, y no solo con la exactitud.

Palabras clave

PalabraQué significa
Exactitudla parte de todos los mensajes que el modelo clasificó bien
Desequilibradauna etiqueta es mucho más frecuente que la otra
Matriz de confusiónuna tabla de respuestas buenas y malas para cada etiqueta
Precisiónde los mensajes señalados, la parte que de verdad era spam
Exhaustividaddel spam real, la parte que se señaló (en inglés, recall)
Umbralla puntuación a partir de la cual se señala un mensaje

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

La exactitud es un número para dos errores

La exactitud cuenta igual todas las respuestas correctas. Sirve cuando las etiquetas son más o menos igual de frecuentes.

Falla cuando la tabla está desequilibrada. Si 40 mensajes de 1000 son spam, un modelo que nunca dice «spam» acierta 960 veces. Acierta el 96 por ciento de las veces y no halla nada de spam.

Puntuar un modelo que nunca dice spam

Comando
docker exec jupyter python3 -c "t=[1]*40+[0]*960; g=[0]*1000; print(sum(a==b for a,b in zip(t,g))/1000)"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Contar las cuatro clases de respuesta

El spam es lo que buscamos: llámalo positivo. Cada mensaje cae en una de cuatro casillas.

Detectado: spam, señalado. Falsa alarma: no es spam, señalado. Pasado por alto: spam, sin señalar. Rechazo correcto: no es spam, sin señalar. Los cuatro recuentos juntos son la matriz de confusión.

Ejemplo resuelto: un filtro con 1000 mensajes

Señalados como spamSin señalar
De verdad spam (40)Detectados: 30Pasados por alto: 10
No es spam (960)Falsas alarmas: 20Rechazos correctos: 940

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Imprimir la matriz, la precisión y la exhaustividad

Comando
docker exec jupyter python3 -c "from sklearn.metrics import confusion_matrix, precision_score, recall_score; t=[1]*40+[0]*960; g=[1]*30+[0]*10+[1]*20+[0]*940; print(confusion_matrix(t,g)); print(round(precision_score(t,g),3), round(recall_score(t,g),3), (30+940)/1000)"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Precisión y exhaustividad preguntan cosas distintas

La precisión pregunta: cuando el filtro dice spam, ¿acierta a menudo? Aquí, 30 de los 50 señalados, o sea 0,6.

La exhaustividad pregunta: del spam real, ¿cuánto halló el filtro? Aquí, 30 de 40, o sea 0,75. La exactitud era 0,97. El filtro es mejor que el que nunca dice spam, pero la exactitud apenas muestra cuánto.

Mover el umbral cambia una por otra

La mayoría de los modelos dan una puntuación, y un umbral la convierte en etiqueta. Si bajas el umbral, se señalan más mensajes. Se detecta más spam, pero también se señala más correo bueno.

Así que la precisión y la exhaustividad tiran en sentidos contrarios, y una persona tiene que elegir. Ejecuta el código y mira cómo se mueven los recuentos.

Cuatro umbrales con diez mensajes

Código: python
# Diez mensajes: la puntuación que dio un modelo (de 0 a 1) y si de verdad era spam.
messages = [
    (0.95, 1), (0.9, 1), (0.8, 0), (0.7, 1), (0.6, 0),
    (0.5, 1), (0.4, 0), (0.3, 0), (0.2, 0), (0.1, 0),
]
for limit in [0.9, 0.7, 0.5, 0.3]:
    caught = 0
    false_alarms = 0
    missed = 0
    for score, spam in messages:
        flagged = score >= limit
        if flagged and spam == 1:
            caught = caught + 1
        if flagged and spam == 0:
            false_alarms = false_alarms + 1
        if not flagged and spam == 1:
            missed = missed + 1
    print("umbral", limit, "detectados", caught, "falsas alarmas", false_alarms, "pasados por alto", missed)
# ¿Qué umbral elegirías para un buzón de correo? ¿Y para un banco?

Ejemplo resuelto: lo que da cada umbral

UmbralDetectadosFalsas alarmasPasados por altoPrecisiónExhaustividad
0.92021.00.5
0.73110.750.75
0.54200.6671.0
0.34400.51.0

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Un error frecuente

Advertencia

Mucha gente cree que el mejor umbral es el de mejor nota en un solo número. No hay mejor umbral sin conocer el coste. Un buzón puede vivir con algo de spam. Un control de fraude no puede dejar pasar ninguno.

Para ir más lejos: el coste del error

Supón que un spam pasado por alto cuesta 1 minuto de lectura y que una falsa alarma cuesta 5 minutos buscando un mensaje perdido. Usa la tabla de los cuatro umbrales.

Calcula los minutos perdidos con cada umbral. ¿Qué umbral cuesta menos? ¿Cambiaría si una falsa alarma costara solo 1 minuto?

Sobre este laboratorio y su código: Laboratorio JupyterLab de ciencia de datos: pandas, Matplotlib y scikit-learn en el navegador

¿Enseñas a una clase? Asigna este módulo a tus alumnos con guía del profesor, tareas con corrección automática y un laboratorio para cada alumno.