Métricas de clasificación de múltiples etiquetas en scikit

19

Estoy tratando de construir un clasificador de etiquetas múltiples para asignar temas a documentos existentes usando scikit

Estoy procesando mis documentos pasándolos a través de las TfidfVectorizeretiquetas MultiLabelBinarizery creando un OneVsRestClassifiercon un SGDClassifierestimador.

Sin embargo, cuando pruebo mi clasificador solo obtengo puntajes de hasta .29, que según lo que he leído es bastante bajo para problemas similares. Probé varias opciones en el TfidfVectorizer, como palabras vacías, unigramas, derivaciones y nada parece cambiar tanto el resultado.

También solía GridSearchCVobtener los mejores parámetros para mi estimador y actualmente no tengo ideas sobre qué probar a continuación.

Al mismo tiempo, por lo que entiendo que no puedo usar scikit.metricscon el OneVsRestClassifiermodo cómo puedo conseguir algunas métricas (F1, precisión, cobertura, etc.) con el fin de averiguar lo que está mal?

¿Podría ser un problema con mi corpus de datos?

Actualización: También he intentado usar CountVectorizery HashingVectorizery la canalización a TfidfTransformerpero los resultados son similares. Así que supongo que el enfoque de la bolsa de palabras está funcionando mejor en el dominio de tokenización y el resto depende del clasificador ...

mobius
fuente
1
¿Qué mide 0.29? ¿Exactitud? ¿Algo más?
Sycorax dice Reinstate Monica
@GeneralAbrial Según la documentación de scikit que se ejecuta scoreen el clasificador,Returns the mean accuracy on the given test data and labels. In multi-label classification, this is the subset accuracy which is a harsh metric since you require for each sample that each label set be correctly predicted.
mobius
¿Es eso lo que has hecho? No queda claro en absoluto de su pregunta que este sea el caso, por lo que es una pregunta perfectamente razonable.
Sycorax dice Reinstate Monica
@GeneralAbrial Sí, esto es lo que he hecho. Perdón por la confusión, estaba tratando de mantener la pregunta en un modo más teórico en lugar de uno de desarrollo.
mobius
¿Puedes agregar tu código aquí? Específicamente, ¿está utilizando sample_weight = "balanceado" para SGD? Pero puede haber otras cosas para tener en cuenta una vez que veamos su código.
Diego

Respuestas:

21

La precisión del subconjunto es de hecho una métrica severa. Para tener una idea de lo bueno o malo que es 0.29, alguna idea:

  • mira cuántas etiquetas tienes un promedio para cada muestra
  • mire el acuerdo entre anotadores, si está disponible (si no, intente ver qué precisión de subconjunto se obtiene cuando es el clasificador)
  • pensar si el tema está bien definido
  • mira cuántas muestras tienes para cada etiqueta

También es posible que desee calcular la puntuación de hamming, para ver si su clasificador no tiene idea, o si es bastante bueno, pero tiene problemas para predecir todas las etiquetas correctamente. Vea a continuación para calcular el puntaje de Hamming.

Al mismo tiempo, por lo que entiendo, no puedo usar scikit.metrics con OneVsRestClassifier, entonces, ¿cómo puedo obtener algunas métricas (F1, Precisión, Recuperación, etc.) para descubrir qué está mal?

Consulte ¿Cómo calcular la precisión / recuperación para la clasificación multiclase-multilabel? . Olvidé si sklearn lo admite, recuerdo que tenía algunas limitaciones, por ejemplo, sklearn no admite etiquetas múltiples para matriz de confusión . Sería una buena idea ver estos números de hecho.


Puntuación de Hamming :

En una configuración de clasificación de múltiples etiquetas , sklearn.metrics.accuracy_scoresolo calcula la precisión del subconjunto (3): es decir, el conjunto de etiquetas pronosticado para una muestra debe coincidir exactamente con el conjunto de etiquetas correspondiente en y_true.

Esta forma de calcular la precisión se denomina a veces, quizás menos ambiguamente, relación de coincidencia exacta (1):

ingrese la descripción de la imagen aquí

Otra forma típica de calcular la precisión se define en (1) y (2), y se conoce de manera menos ambigua como el puntaje de Hamming (4) (ya que está estrechamente relacionado con la pérdida de Hamming), o precisión basada en etiquetas . Se calcula de la siguiente manera:

ingrese la descripción de la imagen aquí

Aquí hay un método de Python para calcular la puntuación de Hamming:

# Code by /programming//users/1953100/william
# Source: /programming//a/32239764/395857
# License: cc by-sa 3.0 with attribution required

import numpy as np

y_true = np.array([[0,1,0],
                   [0,1,1],
                   [1,0,1],
                   [0,0,1]])

y_pred = np.array([[0,1,1],
                   [0,1,1],
                   [0,1,0],
                   [0,0,0]])

def hamming_score(y_true, y_pred, normalize=True, sample_weight=None):
    '''
    Compute the Hamming score (a.k.a. label-based accuracy) for the multi-label case
    /programming//q/32239577/395857
    '''
    acc_list = []
    for i in range(y_true.shape[0]):
        set_true = set( np.where(y_true[i])[0] )
        set_pred = set( np.where(y_pred[i])[0] )
        #print('\nset_true: {0}'.format(set_true))
        #print('set_pred: {0}'.format(set_pred))
        tmp_a = None
        if len(set_true) == 0 and len(set_pred) == 0:
            tmp_a = 1
        else:
            tmp_a = len(set_true.intersection(set_pred))/\
                    float( len(set_true.union(set_pred)) )
        #print('tmp_a: {0}'.format(tmp_a))
        acc_list.append(tmp_a)
    return np.mean(acc_list)

if __name__ == "__main__":
    print('Hamming score: {0}'.format(hamming_score(y_true, y_pred))) # 0.375 (= (0.5+1+0+0)/4)

    # For comparison sake:
    import sklearn.metrics

    # Subset accuracy
    # 0.25 (= 0+1+0+0 / 4) --> 1 if the prediction for one sample fully matches the gold. 0 otherwise.
    print('Subset accuracy: {0}'.format(sklearn.metrics.accuracy_score(y_true, y_pred, normalize=True, sample_weight=None)))

    # Hamming loss (smaller is better)
    # $$ \text{HammingLoss}(x_i, y_i) = \frac{1}{|D|} \sum_{i=1}^{|D|} \frac{xor(x_i, y_i)}{|L|}, $$
    # where
    #  - \\(|D|\\) is the number of samples  
    #  - \\(|L|\\) is the number of labels  
    #  - \\(y_i\\) is the ground truth  
    #  - \\(x_i\\)  is the prediction.  
    # 0.416666666667 (= (1+0+3+1) / (3*4) )
    print('Hamming loss: {0}'.format(sklearn.metrics.hamming_loss(y_true, y_pred))) 

Salidas:

Hamming score: 0.375
Subset accuracy: 0.25
Hamming loss: 0.416666666667

(1) Sorower, Mohammad S. " Una encuesta bibliográfica sobre algoritmos para el aprendizaje de etiquetas múltiples " . Oregon State University, Corvallis (2010).

(2) Tsoumakas, Grigorios e Ioannis Katakis. " Clasificación multi-etiqueta: una visión general " . Departamento de Informática, Universidad Aristóteles de Salónica, Grecia (2006).

(3) Ghamrawi, Nadia y Andrew McCallum. " Clasificación colectiva de etiquetas múltiples " . Actas de la 14ª conferencia internacional de ACM sobre gestión de la información y el conocimiento. ACM, 2005.

(4) Godbole, Shantanu y Sunita Sarawagi. " Métodos discriminatorios para la clasificación de etiquetas múltiples " . Avances en el descubrimiento de conocimiento y la minería de datos. Springer Berlin Heidelberg, 2004. 22-30.

Franck Dernoncourt
fuente
gran respuesta, simplemente me hizo mejor :) ¡Voy a leerlo más a fondo, intentaré el puntaje de Hamming y te responderé!
mobius
Para ser sincero, no está del todo claro para mí cuál es exactamente la precisión del subconjunto (Exact Match Ratio). ¿Podrías explicarme un poco más? Parece que en caso de multiclase, esto es idéntico a recordar.
Poete Maudit
Los hamming_scoreerrores de función en Keras: <ipython-input-34-16066d66dfdd> en hamming_score (y_true, y_pred, normalize, sample_weight) 60 '' '61 acc_list = [] ---> 62 para i en rango (y_true.shape [ 0]): 63 set_true = set (np.where (y_true [i]) [0]) 64 set_pred = set (np.where (y_pred [i]) [0]) TypeError: índice devuelto non-int (tipo NoneType )
rjurney
0

¿El puntaje de 0.29 no es suficiente? ¿Cómo es tu matriz de confusión? ¿Hay algunos temas que no se pueden separar quizás solo mirando el contenido de la palabra?

De lo contrario, intente resolver su problema: suponga que los puntajes bajos son en realidad lo mejor que su clasificador puede hacer en sus datos. Eso significaría que sus documentos no son clasificables utilizando este enfoque.

Para probar esta hipótesis, necesita un conjunto de documentos de prueba con características conocidas de bolsa de palabras (que usted mismo crea). Deberías obtener puntajes del 100%.

Si no lo hace, entonces tiene un error. De lo contrario, necesita un enfoque diferente para clasificar sus documentos. Pregúntese: ¿en qué se diferencian los documentos de las diferentes clases? ¿Necesito mirar otras características de mis documentos, etc.

Ytsen de Boer
fuente
Aparte de los números, siento que 0.29 es bajo. Utilizo el modelo entrenado para predecir temas en documentos que ya he usado en el entrenamiento para probar manualmente el clasificador. No he podido obtener al menos la misma cantidad de temas que el usuario ha ingresado manualmente en el documento. Usualmente solo obtengo un subconjunto de ellos. También en lo que respecta a la cuestión de la matriz de confusión, yo no creo que pueda obtener una matriz de confusión en el uso de los OneVsRestClassifier scikit.metrics ... Voy a comprobarlo, aunque
Mobius