2015-11-13 1 views
10

Accuracy, precision, recall and f-score - это показатели качества системы в машинных системах обучения. Это зависит от матрицы путаницы True/False Positives/Negatives.Расчет точности, повторного вызова и F-оценки за один проход - python

Учитывая бинарная задача классификации, я попытался следующие, чтобы получить функцию, которая возвращает точность, точность, напомним, и диафрагменное оценка:

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 

Но, похоже, я избыточно петельные через набор данных 4 чтобы получить True/False Positives/Negatives.

Также кратное try-excepts, чтобы поймать ZeroDivisionError, является немного избыточным.

Итак, что такое pythonic способ получить подсчеты True/False Positive/Negatives без нескольких циклов через набор данных?

Как я могу pythonically поймать ZeroDivisionError без нескольких попыток-исключений?


Я мог бы также сделать следующее сосчитать True/False позитивы/негативы в одной петле, но есть альтернативный способ без мультипликатора 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 

ответ

10

, что это вещий способ получить отсчеты True/False позитивов/негативов без нескольких петель через набор данных?

Я хотел бы использовать collections.Counter, примерно то, что вы делаете со всеми if с (вы должны использовать elif с, как ваши условия являются взаимоисключающими) в конце:

counts = Counter(zip(predicted, gold)) 

Тогда, например, true_pos = counts[1, 1].

Как я могу pythonically уловить ZeroDivisionError без нескольких try-excepts?

Для начала вы должны (почти) никогда не использовать голый except:. Если вы ловите ZeroDivisionError s, напишите except ZeroDivisionError. Вы также можете рассмотреть подход "look before you leap", проверяя, стоит ли знаменатель 0, прежде чем пытаться делить, например.

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

Прохладный !!!! Я никогда не думал о подсчете кортежей для вычисления точности/отзыва. – alvas

+0

@alvas Я вижу, что вы открыли щедрость, но на самом деле не изменили вопрос; есть ли проблема с моим ответом? – jonrsharpe

+0

@ jonsharpe, я хотел посмотреть, какие другие решения могут возникнуть у людей. В настоящее время у вас есть лучший ответ, скорее всего, щедрость пойдет к вам или, по крайней мере, галочка ответа пойдет вам =) – alvas

4

В зависимости от ваших потребностей, есть несколько библиотек, которые рассчитают точность, напомнит, F-счет и т.д. Один, что я использовал это scikit-learn. Предполагая, что вы выровняли list S фактических и прогнозных значений, то это так же просто, как ...

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

Одним из преимуществ использования этой библиотеки является то, что различные ароматы метрик (например, микро-усреднения, макро-усреднение, взвешенный, двоичный и т. д.) освобождаются из коробки.

4

Это довольно натуральный вариант использования для упаковки bitarray.

import bitarray as bt 

tp = (bt.bitarray(p) & bt.bitarray(g)).count() 
tn = (~bt.bitarray(p) & ~bt.bitarray(g)).count() 
fp = (bt.bitarray(p) & ~bt.bitarray(g)).count() 
fn = (~bt.bitarray(p) & bt.bitarray(g)).count() 

Накладные расходы на изменение типа, но после этого побитовые операции выполняются намного быстрее.

Для 100 экземпляров timeit на моем компьютере дает 0.036 для вашего метода и 0,017 с использованием bitarray на 1000 проходов. Для 1000 экземпляров он равен 0.291 и 0.093. Для 10000, 3,177 и 0,863. Вы поняли эту идею.

Он очень хорошо масштабируется, не используя петли и не должен хранить большое промежуточное представление, создавая временный список кортежей в zip.

Смежные вопросы