Metriche di classificazione multilivello su scikit


19

Sto cercando di creare un classificatore multi-etichetta in modo da assegnare argomenti ai documenti esistenti usando scikit

Sto elaborando i miei documenti passandoli attraverso le TfidfVectorizeretichette attraverso il MultiLabelBinarizere ho creato un OneVsRestClassifiercon uno SGDClassifiercome stimatore.

Tuttavia quando collaudo il mio classificatore ottengo solo punteggi fino a .29 che da quello che ho letto è piuttosto basso per problemi simili. Ho provato diverse opzioni su TfidfVectorizer come stopwords, unigrams, stemming e nulla sembra cambiare così tanto il risultato.

Ho anche usato GridSearchCVper ottenere i migliori parametri per il mio stimatore e attualmente non ho idee su cosa provare dopo.

Allo stesso tempo, da quanto ho capito che non posso utilizzare scikit.metricscon OneVsRestClassifiercosì come posso ottenere alcuni parametri (F1, di precisione, di richiamo, ecc) in modo da capire che cosa è sbagliato?

Potrebbe essere un problema con il mio corpus di dati?

Update: Ho anche provato ad utilizzare CountVectorizered HashingVectorizere pipelining per TfidfTransformerma i risultati sono simili. Quindi immagino che l'approccio bag-of-words stia facendo del suo meglio nel dominio della tokenizzazione e il resto spetta al classificatore ...


1
Cosa misura 0,29? Precisione? Qualcos'altro?
Sycorax dice di ripristinare Monica

@GeneralAbrial Secondo la documentazione di scikit in esecuzione scoresul classificatore,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

È quello che hai fatto? Dalla tua domanda non è affatto chiaro che sia così, quindi è una domanda perfettamente ragionevole.
Sycorax dice di reintegrare Monica il

@GeneralAbrial Sì, questo è quello che ho fatto. Scusate la confusione, stavo cercando di mantenere la domanda in una modalità più teorica piuttosto che in una fase di sviluppo.
mobius,

Puoi aggiungere il tuo codice qui? In particolare stai usando sample_weight = "equilibrato" per SGD? Ma potrebbero esserci altre cose da notare quando vedremo il tuo codice.
Diego,

Risposte:


21

La precisione del sottoinsieme è in effetti una metrica severa. Per avere un'idea di quanto sia buono o cattivo 0,29, qualche idea:

  • guarda quante etichette hai una media per ogni campione
  • guarda l'accordo inter-annotatore, se disponibile (in caso contrario, prova te stesso a vedere quale precisione del sottoinsieme si ottiene quando sei il classificatore)
  • pensa se l'argomento è ben definito
  • guarda quanti campioni hai per ogni etichetta

Potresti anche voler calcolare il punteggio di hamming, per vedere se il tuo classificatore è all'oscuro o è piuttosto decente ma hai problemi a prevedere correttamente tutte le etichette. Vedi sotto per calcolare il punteggio di martellamento.

Allo stesso tempo, da quello che ho capito non posso usare scikit.metrics con OneVsRestClassifier, quindi come posso ottenere alcune metriche (F1, precisione, richiamo ecc.) In modo da capire cosa c'è che non va?

Vedi Come calcolare la precisione / richiamo per la classificazione multiclasse-multilabel? . Ho dimenticato se sklearn lo supporta, ricordo che aveva alcune limitazioni, ad esempio sklearn non supporta multi-etichetta per matrice di confusione . Sarebbe una buona idea vedere davvero questi numeri.


Punteggio di Hamming :

In un'impostazione di classificazione multilabel , sklearn.metrics.accuracy_scorecalcola solo l' accuratezza del sottoinsieme (3): ovvero l'insieme di etichette previsto per un campione deve corrispondere esattamente all'insieme corrispondente di etichette in y_true.

Questo modo di calcolare l'accuratezza è talvolta chiamato, forse meno ambiguamente, rapporto di corrispondenza esatta (1):

inserisci qui la descrizione dell'immagine

Un altro modo tipico per calcolare l'accuratezza è definito in (1) e (2), e meno ambiguamente indicato come il punteggio di Hamming (4) (poiché è strettamente correlato alla perdita di Hamming) o accuratezza basata sull'etichetta ). È calcolato come segue:

inserisci qui la descrizione dell'immagine

Ecco un metodo Python per calcolare il punteggio di 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))) 

Uscite:

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

(1) Sorower, Mohammad S. " Un sondaggio sulla letteratura sugli algoritmi per l'apprendimento multi-etichetta. " Oregon State University, Corvallis (2010).

(2) Tsoumakas, Grigorios e Ioannis Katakis. " Classificazione multi-etichetta: una panoramica. " Dipartimento di Informatica, Università Aristotele di Salonicco, Grecia (2006).

(3) Ghamrawi, Nadia e Andrew McCallum. " Classificazione collettiva multietichetta. " Atti della 14a conferenza internazionale ACM sulla gestione delle informazioni e delle conoscenze. ACM, 2005.

(4) Godbole, Shantanu e Sunita Sarawagi. " Metodi discriminatori per la classificazione multietichettata. " Progressi nella scoperta della conoscenza e nel data mining. Springer Berlin Heidelberg, 2004. 22-30.


ottima risposta, mi ha fatto solo meglio :) Ho intenzione di leggerlo più a fondo, provare il punteggio di Hamming e tornare da te!
mobius,

Ad essere sincero, non mi è del tutto chiaro quale sia esattamente la precisione del sottoinsieme (Exact Match Ratio). Potresti spiegare un po 'di più? Sembra che in caso di multiclasse sia identico da ricordare.
Poete Maudit,

La hamming_scorefunzione si esaurisce su Keras: <ipython-input-34-16066d66dfdd> in hamming_score (y_true, y_pred, normalize, sample_weight) 60 '' '61 acc_list = [] ---> 62 per i nell'intervallo (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: indice restituito non-int (tipo NoneType )
rjurney,

0

Il punteggio di 0.29 non è abbastanza? Com'è la tua matrice di confusione? Ci sono alcuni argomenti che non possono essere separati forse guardando solo la parola contenuto?

Altrimenti, prova a risolvere il problema: ipotizza che i punteggi bassi siano effettivamente i migliori che il tuo classificatore può fare sui tuoi dati. Ciò significherebbe che i tuoi documenti non sono classificabili usando questo approccio.

Per verificare questa ipotesi, è necessario un set di documenti di prova con caratteristiche bag-of-word conosciute (che crei tu stesso). Dovresti ottenere punteggi al 100%.

Se non lo fai, allora hai un bug. In caso contrario, è necessario un approccio diverso per classificare i documenti. Chiediti: in che modo i documenti delle diverse classi differiscono l'uno dall'altro? Devo guardare altre caratteristiche dei miei documenti, ecc.


A parte i numeri, sento che 0,29 è basso. Uso il modello addestrato per prevedere argomenti su documenti che ho già usato nella formazione per testare manualmente il classificatore. Non sono stato in grado di ottenere almeno lo stesso numero di argomenti che l'utente ha inserito manualmente nel documento. Di solito ne ottengo solo un sottoinsieme. Anche per quanto riguarda la domanda sulla matrice di confusione, non credo di poter ottenere una matrice di confusione su OneVsRestClassifier usando scikit.metrics ... Verificherò comunque
mobius
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.