简体   繁体   English

在一次传递中计算精度,召回和F分数 - 蟒蛇

[英]Calculating Precision, Recall and F-score in one pass - python

Accuracy, precision, recall and f-score are measures of a system quality in machine-learning systems. 准确性,精确度,召回率和f-score是机器学习系统中系统质量的度量。 It depends on a confusion matrix of True/False Positives/Negatives. 它取决于真/假阳性/阴性的混淆矩阵。

Given a binary classification task, I have tried the following to get a function that returns accuracy, precision, recall and f-score: 鉴于二进制分类任务,我尝试了以下方法来获得一个返回准确性,精确度,召回率和f分数的函数:

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

But it seems like I have redundantly looped through the dataset 4 times to get the True/False Positives/Negatives. 但似乎我已经多次循环数据集4次以获得真/假阳性/阴性。

Also the multiple try-excepts to catch the ZeroDivisionError is a little redundant. 捕获ZeroDivisionError的多个try-excepts ZeroDivisionError也有点多余。

So what is the pythonic way to get the counts of the True/False Positives/Negatives without multiple loops through the dataset? 那么,在没有多个循环通过数据集的情况下获得真/假阳性/阴性计数的pythonic方法是什么?

How do I pythonically catch the ZeroDivisionError without the multiple try-excepts? 如何在没有多个try- ZeroDivisionError情况下ZeroDivisionError捕获ZeroDivisionError


I could also do the following to count the True/False Positives/Negatives in one loop but is there an alternative way without the multiple if ? 我还可以在一个循环中执行以下操作来计算真/假阳性/阴性,但是if没有倍数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

what is the pythonic way to get the counts of the True/False Positives/Negatives without multiple loops through the dataset? 什么是获得真/假阳性/阴性计数而不通过数据集的多个循环的pythonic方法?

I would use a collections.Counter , roughly what you're doing with all of the if s (you should be using elif s, as your conditions are mutually exclusive) at the end: 我会使用collections.Counter ,大致是你所做的所有if (你应该使用elif s,因为你的条件是相互排斥的)最后:

counts = Counter(zip(predicted, gold))

Then eg true_pos = counts[1, 1] . 然后例如true_pos = counts[1, 1]

How do I pythonically catch the ZeroDivisionError without the multiple try-excepts? 如何在没有多个try-excepts的情况下pythonically捕获ZeroDivisionError?

For a start, you should (almost) never use a bare except: . 首先,你应该(几乎)从不使用裸露的, except: If you're catching ZeroDivisionError s, then write except ZeroDivisionError . 如果您正在捕获ZeroDivisionError ,则写入except ZeroDivisionError You could also consider a "look before you leap" approach, checking whether the denominator is 0 before trying the division, eg 你也可以考虑一个“先看之前”的方法,在尝试除法之前检查分母是否为0 ,例如

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

This is a pretty natural use case for the bitarray package. 这是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()

There's some type conversion overhead, but after that, the bitwise operations are much faster. 有一些类型转换开销,但在那之后,按位操作要快得多。

For 100 instances, timeit on my PC gives 0.036 for your method and 0.017 using bitarray at 1000 passes. 对于100个实例,我的PC上的timeit为您的方法提供0.036,在1000次通过时使用bitarray为0.017。 For 1000 instances, it goes to 0.291 and 0.093. 对于1000个实例,它变为0.291和0.093。 For 10000, 3.177 and 0.863. 对于10000,3.177和0.863。 You get the idea. 你明白了。

It scales pretty well, using no loops, and doesn't have to store a large intermediate representation building a temporary list of tuples in zip . 它很好地扩展,不使用循环,并且不必存储大的中间表示,在zip构建临时的元组列表。

Depending on your needs, there are several libraries that will calculate precision, recall, F-score, etc. One that I have used is scikit-learn . 根据您的需要,有几个库可以计算精度,召回率,F分数等。我使用的是scikit-learn Assuming that you have aligned list s of actual and predicted values, then it is as simple as... 假设您已经对齐了实际值和预测值的list ,那么它就像......一样简单

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

One of the advantages of using this library is that different flavors of metrics (such as micro-averaging, macro-averaging, weighted, binary, etc.) come free out of the box. 使用该库的一个优点是,不同风格的指标(如微观平均,宏观平均,加权,二进制等)都是开箱即用的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM