2015-11-13 49 views
10

Accuracy, precision, recall and f-score sono misure di una qualità del sistema nei sistemi di apprendimento automatico. Dipende da una matrice di confusione di Veri/falsi positivi/negativi.Calcolo della precisione, richiamo e F-score in un passaggio - python

Dato un compito classificazione binaria, ho provato quanto segue per ottenere una funzione che restituisce accuratezza, precisione, richiamo e F-score:

gold = [1] + [0] * 9 
predicted = [1] * 10 

def evaluation(gold, predicted): 
    true_pos = sum(1 for p,g in zip(predicted, gold) if p==1 and g==1) 
    true_neg = sum(1 for p,g in zip(predicted, gold) if p==0 and g==0) 
    false_pos = sum(1 for p,g in zip(predicted, gold) if p==1 and g==0) 
    false_neg = sum(1 for p,g in zip(predicted, gold) if p==0 and g==1) 
    try: 
    recall = true_pos/float(true_pos + false_neg) 
    except: 
    recall = 0 
    try: 
    precision = true_pos/float(true_pos + false_pos) 
    except: 
    precision = 0 
    try: 
    fscore = 2*precision*recall/(precision + recall) 
    except: 
    fscore = 0 
    try: 
    accuracy = (true_pos + true_neg)/float(len(gold)) 
    except: 
    accuracy = 0 
    return accuracy, precision, recall, fscore 

ma sembra che ho ridondante in loop con il set di dati 4 volte per ottenere i veri/falsi positivi/negativi.

Anche il multiplo try-excepts per catturare lo ZeroDivisionError è un po 'ridondante.

Quindi qual è il modo pitone per ottenere i conteggi dei Veri/falsi positivi/negativi senza loop multipli attraverso il set di dati?

Come faccio a catturare Pythonic lo ZeroDivisionError senza i molteplici errori di prova?


Potrei anche fare quanto segue per contare le Vero/Falso positivi/negativi in ​​un loop, ma c'è un modo alternativo senza il multiplo if?:

for p,g in zip(predicted, gold): 
    if p==1 and g==1: 
     true_pos+=1 
    if p==0 and g==0: 
     true_neg+=1 
    if p==1 and g==0: 
     false_pos+=1 
    if p==0 and g==1: 
     false_neg+=1 

risposta

10

qual è il modo divinatorio per ottenere i conteggi dei Vero/Falso positivi/negativi senza cicli multipli attraverso il set di dati?

userei un collections.Counter, più o meno quello che stai facendo con tutti i if s (si dovrebbe utilizzare elif s, come le vostre condizioni sono mutuamente esclusivi) alla fine:

counts = Counter(zip(predicted, gold)) 

Quindi ad es true_pos = counts[1, 1].

Come faccio pythonically prendo lo ZeroDivisionError senza le molteplici Try-eccettua?

Per cominciare, non si dovrebbe (quasi) mai usare un except:. Se stai prendendo ZeroDivisionError s, quindi scrivere except ZeroDivisionError. Potresti anche considerare un approccio "look before you leap", controllando se il denominatore è 0 prima di provare la divisione, ad es.

accuracy = (true_pos + true_neg)/float(len(gold)) if gold else 0 
+0

Cool !!!! Non ho mai pensato di contare le tuple per il calcolo di precisione/richiamo. – alvas

+0

@alvas Vedo che hai aperto una taglia, ma in realtà non ho cambiato la domanda; c'è un problema con la mia risposta? – jonrsharpe

+0

@jonsharpe, volevo vedere quali altre soluzioni le persone possono trovare. Al momento, hai la risposta migliore, molto probabilmente la taglia verrà indirizzata a te o almeno il segno di spunta della risposta verrà inviato a te =) – alvas

4

A seconda delle esigenze, ci sono diverse librerie che calcola la precisione, di richiamo, F-score, ecc Uno che mi avete usato è scikit-learn. Supponendo che è stato allineato list s di valori effettivi e previsti, allora è semplice come ...

from sklearn.metrics import precision_recall_fscore_support as pr 
bPrecis, bRecall, bFscore, bSupport = pr(gold, predicted, average='binary') 

Uno dei vantaggi derivanti dall'utilizzo di questa libreria è che i diversi gusti di metriche (come micro-media, macro-media, ponderata, binaria, ecc.) sono disponibili gratuitamente.

4

Questo è un caso di uso piuttosto naturale per il pacchetto bitarray.

C'è qualche tipo di overhead di conversione, ma dopo, le operazioni bit a bit sono molto più veloci.

Per 100 istanze, timeit sul mio PC fornisce 0,036 per il metodo e 0,017 utilizzando bitarray a 1000 passaggi. Per 1000 istanze, passa a 0,291 e 0,093. Per 10000, 3.177 e 0.863. Hai un'idea.

È scalabile abbastanza bene, senza loop e non deve memorizzare una grande rappresentazione intermedia che crea un elenco temporaneo di tuple in zip.