Вычисление точности, повторения и F-оценки за один проход - python

Точность, точность, отзыв и f-оценка - это показатели качества системы в машинных системах. Это зависит от матрицы путаницы True/False Positives/Negatives.

Учитывая задачу двоичной классификации, я попробовал следующее получить функцию, которая возвращает точность, точность, отзыв и 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

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

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

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

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


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

Ответ 1

что такое питонический способ получить значения True/False Положительные/отрицательные значения без нескольких циклов через набор данных?

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

counts = Counter(zip(predicted, gold))

Затем, например, true_pos = counts[1, 1].

Как я могу pythonically поймать ZeroDivisionError без множественного попробуйте-excepts?

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

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

Ответ 2

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

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

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

Ответ 3

Это довольно естественный вариант использования 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.