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

alv*_*vas 10 python list machine-learning try-except precision-recall

准确性,精确度,召回率和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
Run Code Online (Sandbox Code Playgroud)

但似乎我已经多次循环数据集4次以获得真/假阳性/阴性.

try-excepts捕获的倍数ZeroDivisionError也有点多余.

那么,在没有多个循环通过数据集的情况下获得真/假阳性/阴性计数的pythonic方法是什么?

如何在ZeroDivisionError不使用多个try-excepts 的情况下进行pythonically捕获?


我还可以在一个循环中执行以下操作来计算真/假阳性/阴性但是有没有多重的替代方法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
Run Code Online (Sandbox Code Playgroud)

jon*_*rpe 11

什么是获得真/假阳性/阴性计数而不通过数据集的多个循环的pythonic方法?

我会在最后使用a collections.Counter,大致你正在做的所有ifs(你应该使用elifs,因为你的条件是相互排斥的):

counts = Counter(zip(predicted, gold))
Run Code Online (Sandbox Code Playgroud)

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

如何在没有多个try-excepts的情况下pythonically捕获ZeroDivisionError?

首先,你应该(几乎)从不使用裸机except:.如果你正在追赶ZeroDivisionError,那就写吧except ZeroDivisionError.你也可以考虑一个"先看一跳"的方法,检查分母是否0在尝试分裂之前,例如

accuracy = (true_pos + true_neg) / float(len(gold)) if gold else 0
Run Code Online (Sandbox Code Playgroud)


小智 5

这是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()
Run Code Online (Sandbox Code Playgroud)

有一些类型转换开销,但在那之后,按位操作要快得多.

对于100个实例,我的PC上的timeit为您的方法提供0.036,在1000次通过时使用bitarray为0.017.对于1000个实例,它变为0.291和0.093.对于10000,3.177和0.863.你明白了.

它很好地扩展,不使用循环,并且不必存储构建临时元组列表的大型中间表示zip.