Publicado el 5 min de lectura

Evalúa la clasificación de incidencias con una matriz de confusión

En esta página

Un clasificador de IA puede acertar el 80 % y fallar en la mitad de las solicitudes de acceso. Antes de conectarlo a una cola de trabajo, examina los errores detrás de esa cifra.

Crea un evaluador local para tres etiquetas. Comprueba la calidad de las predicciones, no el formato de exportación. Basta con la biblioteca estándar de Python; los datos sintéticos no requieren cuenta de un modelo ni información de clientes.

Tres bandejas de incidencias identificadas con símbolos de conversación, recibo y llave; una lupa examina dos tarjetas ámbar junto a una pequeña matriz de piezas.

1. Fija las reglas de clasificación y las respuestas de referencia

Define un único destino por incidencia:

Etiqueta Regla de asignación Ejemplo
general Preguntas sobre el producto sin problemas de facturación o acceso ¿Dónde está la guía de configuración?
billing Cobros, facturas o reembolsos Me han cobrado dos veces.
access Problemas de inicio de sesión, contraseña o permisos Mi enlace de restablecimiento ha caducado.

Para solicitudes mixtas, acuerda la prioridad con soporte antes de etiquetar. Los revisores deben asignar las etiquetas de referencia sin ver las predicciones. Conserva identificadores estables y elimina los detalles sensibles.

Utiliza un conjunto de desarrollo para cambiar el prompt y otro de prueba, sin tocar, para la comparación final. Así aplicas el principio de separación de la guía de scikit-learn sobre fuga de datos a la clasificación mediante prompts. No incluyas las respuestas de referencia de prueba en la entrada del clasificador.

Si ya tienes un flujo de clasificación de texto, guarda sus predicciones por identificador. Los datos de abajo incluyen predicciones ficticias para probar el evaluador, no pruebas del rendimiento de ningún modelo.

2. Interpreta la matriz y la sensibilidad

Aquí, las filas de la matriz son las etiquetas revisadas y las columnas, las predicciones, siguiendo la convención de scikit-learn. La diagonal contiene las asignaciones correctas; las otras celdas muestran errores. Consulta nuestra explicación de la matriz de confusión para más contexto.

La exactitud es el número de asignaciones correctas dividido entre todas las incidencias. La sensibilidad por clase, o recall, divide sus asignaciones correctas entre el número real de incidencias de esa clase. El recall macro promedia esas sensibilidades con el mismo peso, según la documentación oficial de recall. Así, la cola mayor no domina este resumen.

Para el ejercicio, fija un criterio de revisión: recall macro de al menos 0,80 y recall de acceso de al menos 0,90. Son decisiones ilustrativas del flujo de trabajo, no estándares universales de despliegue.

3. Ejecuta un evaluador sin dependencias

Guarda este código como evaluate_ticket_routing.py. Utiliza Python 3.10 o posterior. Conserva los valores de las etiquetas y el código sin cambios en ambos idiomas.

LABELS = ("general", "billing", "access")
# ticket_id: (reviewed label, synthetic model prediction)
FIXTURE = {
    "t1": ("general", "general"),
    "t2": ("general", "general"),
    "t3": ("general", "general"),
    "t4": ("general", "general"),
    "t5": ("general", "general"),
    "t6": ("general", "general"),
    "t7": ("billing", "billing"),
    "t8": ("billing", "general"),
    "t9": ("access", "access"),
    "t10": ("access", "general"),
}
GOLD = {key: pair[0] for key, pair in FIXTURE.items()}
PREDICTED = {key: pair[1] for key, pair in FIXTURE.items()}


def evaluate(gold, predicted):
    if set(gold) != set(predicted):
        raise ValueError("missing or extra ticket IDs")
    if any(v not in LABELS for v in [*gold.values(), *predicted.values()]):
        raise ValueError("unknown label")
    matrix = [[0] * len(LABELS) for _ in LABELS]
    for key, actual in gold.items():
        matrix[LABELS.index(actual)][LABELS.index(predicted[key])] += 1
    support = [sum(row) for row in matrix]
    if not all(support):
        raise ValueError("every class needs a gold example")
    recall = {label: matrix[i][i] / support[i]
              for i, label in enumerate(LABELS)}
    accuracy = sum(matrix[i][i] for i in range(len(LABELS))) / len(gold)
    return matrix, accuracy, recall


def report(name, predicted):
    matrix, accuracy, recall = evaluate(GOLD, predicted)
    macro = sum(recall.values()) / len(LABELS)
    print(name)
    print("columns:", ", ".join(LABELS))
    for label, row in zip(LABELS, matrix):
        print(f"{label}: {row} recall={recall[label]:.3f}")
    print(f"accuracy={accuracy:.3f} macro_recall={macro:.3f}")
    ready = macro >= 0.80 and recall["access"] >= 0.90
    print("review_gate=" + ("PASS" if ready else "HOLD"))


if __name__ == "__main__":
    report("candidate", PREDICTED)
    report("constant baseline", {key: "general" for key in GOLD})
python3 evaluate_ticket_routing.py

Salida esperada:

candidate
columns: general, billing, access
general: [6, 0, 0] recall=1.000
billing: [1, 1, 0] recall=0.500
access: [1, 0, 1] recall=0.500
accuracy=0.800 macro_recall=0.667
review_gate=HOLD
constant baseline
columns: general, billing, access
general: [6, 0, 0] recall=1.000
billing: [2, 0, 0] recall=0.000
access: [2, 0, 0] recall=0.000
accuracy=0.600 macro_recall=0.333
review_gate=HOLD

4. Valida el resultado antes de confiar en él

El candidato acierta ocho de diez incidencias, pero envía una de facturación y otra de acceso a general. Ambas clases minoritarias tienen un recall de 0,50, por lo que el criterio retiene al candidato para revisión.

La referencia constante asigna cada incidencia a general: un 60 % de exactitud, pero recall cero para ambas clases minoritarias. Scikit-learn documenta los predictores constantes como comparaciones básicas. Elige la referencia con datos de desarrollo o entrenamiento, nunca con el conjunto de prueba final.

Sustituye PREDICTED por dict(GOLD) para comprobar el evaluador: la exactitud y el recall macro deberían alcanzar 1.000, con PASS. Esto solo comprueba la aritmética. Aunque imprima HOLD, el programa termina correctamente; no bloquea despliegues mediante su código de salida.

5. Resuelve problemas y amplía con cuidado

  • Identificadores ausentes o adicionales: compara las predicciones con la lista fija de entradas; nunca descartes en silencio las incidencias sin respuesta.
  • Etiqueta desconocida: exige uno de los tres valores permitidos. No conviertas automáticamente las respuestas inválidas en general.
  • Una clase no tiene ejemplos: añade ejemplos revisados; la falta de cobertura no equivale a un recall perfecto.
  • Resultados inesperadamente perfectos: busca etiquetas filtradas al modelo o incidencias repetidas entre desarrollo y prueba.

Dos ejemplos por clase minoritaria no demuestran que el sistema esté listo para producción. Recoge más incidencias representativas, informa del número de ejemplos por clase y revisa los fallos. Cambia una regla de asignación o instrucción del prompt, repite las comprobaciones de desarrollo y después evalúa el conjunto de prueba sin tocar. Para entender el compromiso con las falsas alarmas, consulta recall frente a precisión.

Conclusión práctica

Compara con una referencia, examina los errores fuera de la diagonal y fija expectativas por clase antes de automatizar. La matriz identifica las colas que necesitan atención; la exactitud global por sí sola no lo hace.

Artículos relacionados

Últimos artículos