¿Cómo calcular la precisión, recuperación, exactitud y puntuación f1 para el caso multiclase con scikit learn?

109

Estoy trabajando en un problema de análisis de sentimientos, los datos se ven así:

label instances
    5    1190
    4     838
    3     239
    1     204
    2     127

Entonces mis datos no están balanceados ya que 1190 instancesestán etiquetados con 5. Para la clasificación, estoy usando el SVC de scikit . El problema es que no sé cómo equilibrar mis datos de la manera correcta para calcular con precisión la precisión, la recuperación, la exactitud y la puntuación f1 para el caso multiclase. Entonces probé los siguientes enfoques:

Primero:

    wclf = SVC(kernel='linear', C= 1, class_weight={1: 10})
    wclf.fit(X, y)
    weighted_prediction = wclf.predict(X_test)

print 'Accuracy:', accuracy_score(y_test, weighted_prediction)
print 'F1 score:', f1_score(y_test, weighted_prediction,average='weighted')
print 'Recall:', recall_score(y_test, weighted_prediction,
                              average='weighted')
print 'Precision:', precision_score(y_test, weighted_prediction,
                                    average='weighted')
print '\n clasification report:\n', classification_report(y_test, weighted_prediction)
print '\n confussion matrix:\n',confusion_matrix(y_test, weighted_prediction)

Segundo:

auto_wclf = SVC(kernel='linear', C= 1, class_weight='auto')
auto_wclf.fit(X, y)
auto_weighted_prediction = auto_wclf.predict(X_test)

print 'Accuracy:', accuracy_score(y_test, auto_weighted_prediction)

print 'F1 score:', f1_score(y_test, auto_weighted_prediction,
                            average='weighted')

print 'Recall:', recall_score(y_test, auto_weighted_prediction,
                              average='weighted')

print 'Precision:', precision_score(y_test, auto_weighted_prediction,
                                    average='weighted')

print '\n clasification report:\n', classification_report(y_test,auto_weighted_prediction)

print '\n confussion matrix:\n',confusion_matrix(y_test, auto_weighted_prediction)

Tercero:

clf = SVC(kernel='linear', C= 1)
clf.fit(X, y)
prediction = clf.predict(X_test)


from sklearn.metrics import precision_score, \
    recall_score, confusion_matrix, classification_report, \
    accuracy_score, f1_score

print 'Accuracy:', accuracy_score(y_test, prediction)
print 'F1 score:', f1_score(y_test, prediction)
print 'Recall:', recall_score(y_test, prediction)
print 'Precision:', precision_score(y_test, prediction)
print '\n clasification report:\n', classification_report(y_test,prediction)
print '\n confussion matrix:\n',confusion_matrix(y_test, prediction)


F1 score:/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:676: DeprecationWarning: The default `weighted` averaging is deprecated, and from version 0.18, use of precision, recall or F-score with multiclass or multilabel data or pos_label=None will result in an exception. Please set an explicit value for `average`, one of (None, 'micro', 'macro', 'weighted', 'samples'). In cross validation use, for instance, scoring="f1_weighted" instead of scoring="f1".
  sample_weight=sample_weight)
/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:1172: DeprecationWarning: The default `weighted` averaging is deprecated, and from version 0.18, use of precision, recall or F-score with multiclass or multilabel data or pos_label=None will result in an exception. Please set an explicit value for `average`, one of (None, 'micro', 'macro', 'weighted', 'samples'). In cross validation use, for instance, scoring="f1_weighted" instead of scoring="f1".
  sample_weight=sample_weight)
/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:1082: DeprecationWarning: The default `weighted` averaging is deprecated, and from version 0.18, use of precision, recall or F-score with multiclass or multilabel data or pos_label=None will result in an exception. Please set an explicit value for `average`, one of (None, 'micro', 'macro', 'weighted', 'samples'). In cross validation use, for instance, scoring="f1_weighted" instead of scoring="f1".
  sample_weight=sample_weight)
 0.930416613529

Sin embargo, recibo advertencias como esta:

/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:1172:
DeprecationWarning: The default `weighted` averaging is deprecated,
and from version 0.18, use of precision, recall or F-score with 
multiclass or multilabel data or pos_label=None will result in an 
exception. Please set an explicit value for `average`, one of (None, 
'micro', 'macro', 'weighted', 'samples'). In cross validation use, for 
instance, scoring="f1_weighted" instead of scoring="f1"

¿Cómo puedo tratar correctamente mis datos desequilibrados para calcular correctamente las métricas del clasificador?

new_with_python
fuente
Entonces, ¿por qué no agregar un averageparámetro en el tercer caso?
yangjie
1
@yangjie, no lo sé. Solo verifico la documentación pero no entiendo cómo usar correctamente las métricas para datos desequilibrados. ¿Podría darnos una explicación más amplia y un ejemplo ?. ¡Gracias!
new_with_python

Respuestas:

164

Creo que hay mucha confusión sobre qué pesos se utilizan para qué. No estoy seguro de saber con precisión qué es lo que te molesta, así que voy a cubrir diferentes temas, ten paciencia;).

Pesos de clase

Los pesos del class_weightparámetro se utilizan para entrenar al clasificador . No se utilizan en el cálculo de ninguna de las métricas que está utilizando : con diferentes pesos de clase, los números serán diferentes simplemente porque el clasificador es diferente.

Básicamente, en todos los clasificadores de scikit-learn, los pesos de las clases se utilizan para indicarle a su modelo qué tan importante es una clase. Eso significa que durante el entrenamiento, el clasificador hará un esfuerzo adicional para clasificar adecuadamente las clases con pesos altos.
Cómo lo hacen es específico del algoritmo. Si desea detalles sobre cómo funciona para SVC y el documento no tiene sentido para usted, no dude en mencionarlo.

Las métricas

Una vez que tenga un clasificador, querrá saber qué tan bien está funcionando. Aquí se pueden utilizar las métricas que usted ha mencionado: accuracy, recall_score, f1_score...

Por lo general, cuando la distribución de clases no está equilibrada, la precisión se considera una mala elección, ya que otorga puntuaciones altas a los modelos que solo predicen la clase más frecuente.

No detallaré todas estas métricas, pero tenga en cuenta que, a excepción de accuracy, se aplican naturalmente a nivel de clase: como puede ver en este printinforme de clasificación, están definidas para cada clase. Se basan en conceptos como true positiveso false negativeque requieren definir qué clase es la positiva .

             precision    recall  f1-score   support

          0       0.65      1.00      0.79        17
          1       0.57      0.75      0.65        16
          2       0.33      0.06      0.10        17
avg / total       0.52      0.60      0.51        50

La advertencia

F1 score:/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:676: DeprecationWarning: The 
default `weighted` averaging is deprecated, and from version 0.18, 
use of precision, recall or F-score with multiclass or multilabel data  
or pos_label=None will result in an exception. Please set an explicit 
value for `average`, one of (None, 'micro', 'macro', 'weighted', 
'samples'). In cross validation use, for instance, 
scoring="f1_weighted" instead of scoring="f1".

Recibe esta advertencia porque está utilizando la puntuación f1, la recuperación y la precisión sin definir cómo se deben calcular. La pregunta podría reformularse: del informe de clasificación anterior, ¿cómo se genera un número global para la puntuación f1? Tú podrías:

  1. Tome el promedio de la puntuación f1 para cada clase: ese es el avg / totalresultado anterior. También se llama promediado macro .
  2. Calcule el puntaje f1 utilizando el recuento global de verdaderos positivos / falsos negativos, etc. (se suma el número de verdaderos positivos / falsos negativos para cada clase). Aka micro promediación.
  3. Calcule un promedio ponderado de la puntuación f1. El uso 'weighted'de scikit-learn pesará el puntaje f1 con el apoyo de la clase: cuantos más elementos tenga una clase, más importante será el puntaje f1 para esta clase en el cálculo.

Estas son 3 de las opciones en scikit-learn, la advertencia está ahí para decirle que debe elegir una . Por lo tanto, debe especificar un averageargumento para el método de puntuación.

El que elija depende de cómo desee medir el rendimiento del clasificador: por ejemplo, el macropromedio no tiene en cuenta el desequilibrio de clase y la puntuación f1 de la clase 1 será tan importante como la puntuación f1 de la clase. 5. Sin embargo, si usa el promedio ponderado, obtendrá más importancia para la clase 5.

Toda la especificación del argumento en estas métricas no es muy clara en scikit-learn en este momento, mejorará en la versión 0.18 de acuerdo con los documentos. Están eliminando algunos comportamientos estándar no obvios y están emitiendo advertencias para que los desarrolladores lo noten.

Calcular puntuaciones

Lo último que quiero mencionar (no dude en omitirlo si es consciente de ello) es que las puntuaciones solo son significativas si se calculan sobre datos que el clasificador nunca ha visto . Esto es extremadamente importante ya que cualquier puntaje que obtenga sobre los datos que se usaron para ajustar el clasificador es completamente irrelevante.

Esta es una forma de hacerlo usando StratifiedShuffleSplit, que le brinda divisiones aleatorias de sus datos (después de barajar) que preservan la distribución de la etiqueta.

from sklearn.datasets import make_classification
from sklearn.cross_validation import StratifiedShuffleSplit
from sklearn.metrics import accuracy_score, f1_score, precision_score, recall_score, classification_report, confusion_matrix

# We use a utility to generate artificial classification data.
X, y = make_classification(n_samples=100, n_informative=10, n_classes=3)
sss = StratifiedShuffleSplit(y, n_iter=1, test_size=0.5, random_state=0)
for train_idx, test_idx in sss:
    X_train, X_test, y_train, y_test = X[train_idx], X[test_idx], y[train_idx], y[test_idx]
    svc.fit(X_train, y_train)
    y_pred = svc.predict(X_test)
    print(f1_score(y_test, y_pred, average="macro"))
    print(precision_score(y_test, y_pred, average="macro"))
    print(recall_score(y_test, y_pred, average="macro"))    

Espero que esto ayude.

ldirer
fuente
Para una multiclase, ¿cómo se especifica un peso de clase? Por ejemplo, ¿qué significa un class_weight={1:10}dato que tiene 3 clases?
Aziz Javed
¿Hay alguna forma de obtener puntajes de precisión en las etiquetas?
Ankur Sinha
¿Puedes explicar cómo funciona micro con más claridad? Además, no mencionas nada sobre binario
humilde
Para mí, la reproducción aleatoria estratificada estaba creando problemas, así que cambié de nuevo a la división de prueba de tren como estaba mostrando ValueError: The least populated class in y has only 1 member, which is too few. The minimum number of labels for any class cannot be less than 2.. Está funcionando bien con la división de prueba de tren, pero ¿alguien puede ayudarme por qué recibo este error con SSS? Gracias.
Akash Kandpal
Hola, probé su código pero tengo este mensaje de error C: \ Users \\ Anaconda3 \ lib \ site-packages \ sklearn \ metrics \ class.py: 976: Deprecation Advertencia: A partir de la versión 0.18, la entrada binaria no se manejará especialmente cuando se use precisión / recuerdo / puntuación F promediados. Utilice average = 'binary' para informar solo el rendimiento positivo de la clase. 'rendimiento de clase positivo.',
Advertencia de
73

Muchas respuestas muy detalladas aquí, pero no creo que esté respondiendo las preguntas correctas. Según entiendo la pregunta, hay dos preocupaciones:

  1. ¿Cómo califico un problema multiclase?
  2. ¿Cómo trato los datos desequilibrados?

1.

Puede utilizar la mayoría de las funciones de puntuación en scikit-learn tanto con problemas multiclase como con problemas de una sola clase. Ex.:

from sklearn.metrics import precision_recall_fscore_support as score

predicted = [1,2,3,4,5,1,2,1,1,4,5] 
y_test = [1,2,3,4,5,1,2,1,1,4,1]

precision, recall, fscore, support = score(y_test, predicted)

print('precision: {}'.format(precision))
print('recall: {}'.format(recall))
print('fscore: {}'.format(fscore))
print('support: {}'.format(support))

De esta manera terminas con números tangibles e interpretables para cada una de las clases.

| Label | Precision | Recall | FScore | Support |
|-------|-----------|--------|--------|---------|
| 1     | 94%       | 83%    | 0.88   | 204     |
| 2     | 71%       | 50%    | 0.54   | 127     |
| ...   | ...       | ...    | ...    | ...     |
| 4     | 80%       | 98%    | 0.89   | 838     |
| 5     | 93%       | 81%    | 0.91   | 1190    |

Luego...

2.

... puede saber si los datos desbalanceados son un problema. Si la puntuación para las clases menos representadas (clase 1 y 2) es menor que para las clases con más muestras de entrenamiento (clase 4 y 5), entonces sabrá que los datos desequilibrados son de hecho un problema y puede actuar en consecuencia, ya que descrito en algunas de las otras respuestas en este hilo. Sin embargo, si la misma distribución de clases está presente en los datos que desea predecir, sus datos de entrenamiento desequilibrados son un buen representante de los datos y, por lo tanto, el desequilibrio es algo bueno.

wonderkid2
fuente
1
Gran publicación y bien dicho. Gracias
Alvis
1
Hola, solo una pregunta de seguimiento: ¿cómo imprimiste las etiquetas usando precision_recall_fscore_support? ¿Las etiquetas se imprimen por encargo?
BigD
@BigD Sí, consulte scikit-learn.org/stable/modules/generated/… al final. Establezca average=Noney defina las etiquetas, luego obtendrá la métrica que está buscando, para cada una de sus etiquetas especificadas.
wonderkid2
¿Hay alguna forma de obtener puntajes de precisión en las etiquetas?
Ankur Sinha
@trollster, no estoy seguro de lo que quieres decir. ¿No es lo que muestro en la respuesta puntajes de precisión por etiquetas?
wonderkid2
16

Pregunta planteada

Respondiendo a la pregunta '¿Qué métrica debería usarse para la clasificación de clases múltiples con datos desequilibrados?': Medida Macro-F1. También se pueden utilizar Macro Precision y Macro Recall, pero no son tan fáciles de interpretar como para la clasificación binaria, ya están incorporadas en la medida F, y el exceso de métricas complica la comparación de métodos, ajuste de parámetros, etc.

El micropromedio es sensible al desequilibrio de clases: si su método, por ejemplo, funciona bien para las etiquetas más comunes y estropea totalmente otras, las métricas micropromediadas muestran buenos resultados.

El promedio de ponderación no es adecuado para datos desequilibrados, porque pondera por conteos de etiquetas. Además, es muy poco interpretable e impopular: por ejemplo, no se menciona un promedio de este tipo en la siguiente encuesta muy detallada que recomiendo encarecidamente revisar:

Sokolova, Marina y Guy Lapalme. "Un análisis sistemático de medidas de desempeño para tareas de clasificación". Tratamiento y gestión de la información 45.4 (2009): 427-437.

Pregunta específica de la aplicación

Sin embargo, volviendo a su tarea, investigaría 2 temas:

  1. métricas que se utilizan comúnmente para su tarea específica: permite (a) comparar su método con otros y comprender si hace algo mal, y (b) no explorar esto por sí mismo y reutilizar los hallazgos de otra persona;
  2. el costo de los diferentes errores de sus métodos, por ejemplo, el caso de uso de su aplicación puede depender solo de revisiones de 4 y 5 estrellas, en este caso, una buena métrica debe contar solo estas 2 etiquetas.

Métricas de uso común. Como puedo inferir después de revisar la literatura, hay 2 métricas de evaluación principales:

  1. Precisión , que se utiliza, por ejemplo, en

Yu, April y Daryl Chang. "Predicción de sentimiento multiclase usando Yelp Business".

( enlace ): tenga en cuenta que los autores trabajan con casi la misma distribución de calificaciones, consulte la Figura 5.

Pang, Bo y Lillian Lee. "Ver estrellas: aprovechar las relaciones de clase para la categorización de sentimientos con respecto a las escalas de calificación". Actas de la 43ª Reunión Anual de la Asociación de Lingüística Computacional. Asociación de Lingüística Computacional, 2005.

( enlace )

  1. MSE (o, con menos frecuencia, error absoluto medio - MAE ); consulte, por ejemplo,

Lee, Moontae y R. Grafe. "Análisis de sentimiento multiclase con reseñas de restaurantes". Proyectos finales de CS N 224 (2010).

( enlace ): exploran tanto la precisión como el MSE, considerando que este último es mejor

Pappas, Nikolaos, Rue Marconi y Andrei Popescu-Belis. "Explicación de las estrellas: aprendizaje ponderado de instancias múltiples para el análisis de sentimientos basado en aspectos". Actas de la Conferencia de 2014 sobre métodos empíricos en el procesamiento del lenguaje natural. No. EPFL-CONF-200899. 2014.

( enlace ): utilizan scikit-learn para la evaluación y los enfoques de referencia y afirman que su código está disponible; sin embargo, no puedo encontrarlo, así que si lo necesita, escriba una carta a los autores, el trabajo es bastante nuevo y parece estar escrito en Python.

Costo de diferentes errores . Si le importa más evitar errores graves, por ejemplo, asignar una reseña de 1 estrella a 5 estrellas o algo así, mire MSE; si la diferencia importa, pero no tanto, pruebe MAE, ya que no cuadra la diferencia; de lo contrario, manténgase con precisión.

Acerca de los enfoques, no de las métricas

Pruebe los enfoques de regresión, por ejemplo, SVR , ya que generalmente superan a los clasificadores multiclase como SVC u OVA SVM.

Nikita Astrakhantsev
fuente
13

En primer lugar, es un poco más difícil usar solo el análisis de conteo para saber si sus datos están desequilibrados o no. Por ejemplo: ¿1 de cada 1000 observaciones positivas es solo un ruido, un error o un avance en la ciencia? Nunca sabes.
Por lo tanto, siempre es mejor utilizar todo su conocimiento disponible y elegir su estado con prudencia.

Bien, ¿y si está realmente desequilibrado?
Una vez más, mire sus datos. A veces puedes encontrar una o dos observaciones multiplicadas por cien veces. A veces es útil crear estas observaciones falsas de una clase.
Si todos los datos están limpios, el siguiente paso es usar ponderaciones de clase en el modelo de predicción.

Entonces, ¿qué pasa con las métricas multiclase?
En mi experiencia, no se suele utilizar ninguna de sus métricas. Hay dos razones principales.
Primero: siempre es mejor trabajar con probabilidades que con predicciones sólidas (porque ¿de qué otra manera podrías separar modelos con predicción 0.9 y 0.6 si ambos te dan la misma clase?)
Y segundo: es mucho más fácil comparar tus modelos de predicción y construir nuevos los que dependen de una sola buena métrica.
Desde mi experiencia, podría recomendar logloss o MSE (o simplemente significar error al cuadrado).

¿Cómo corregir las advertencias de sklearn?
Simplemente (como observó Yangjie) sobrescriba el averageparámetro con uno de estos valores: 'micro'(calcular métricas globalmente), 'macro'(calcular métricas para cada etiqueta) o 'weighted'(igual que la macro pero con pesos automáticos).

f1_score(y_test, prediction, average='weighted')

Todas sus advertencias vinieron después de llamar a funciones de métricas con un averagevalor predeterminado 'binary'que es inapropiado para la predicción multiclase.
¡Buena suerte y diviértete con el aprendizaje automático!

Editar:
encontré otra recomendación del respondedor para cambiar a enfoques de regresión (por ejemplo, SVR) con la que no estoy de acuerdo. Por lo que recuerdo, ni siquiera existe una regresión multiclase. Sí, hay regresión de etiquetas múltiples que es muy diferente y sí, en algunos casos es posible cambiar entre regresión y clasificación (si las clases se ordenaron de alguna manera) pero es bastante raro.

Lo que recomendaría (en el ámbito de scikit-learn) es probar otras herramientas de clasificación muy poderosas: aumento de gradiente , bosque aleatorio (mi favorito), KNeighbors y muchas más.

Después de eso, puede calcular la media aritmética o geométrica entre las predicciones y la mayoría de las veces obtendrá un resultado aún mejor.

final_prediction = (KNNprediction * RFprediction) ** 0.5
Vlad Mironov
fuente
1
> "cambiar entre regresión y clasificación (si las clases se ordenaron de alguna manera) pero es bastante raro" Es el caso: 5> 4> 3> 2> 1. Le sugiero que eche un vistazo a los artículos para esta tarea - hay muchos enfoques de regresión y clasificación para la tarea (a veces en el mismo trabajo).
Nikita Astrakhantsev
Entonces ni siquiera es una clasificación multiclase, sino una simple regresión.
Vlad Mironov
Sí, internamente o desde el punto de vista del ML, es una regresión, pero en el paso final convertimos los resultados de la regresión en etiquetas, por lo que es una clasificación multiclase, desde el punto de vista del usuario o de la aplicación.
Nikita Astrakhantsev