Precision, recall and F1 with the zero cases

Easy8 min10 hidden tests

A camera model on a bottling line flags cracked bottles. At the end of a shift you have three counts: true positives tp (cracked bottles it flagged), false positives fp (good bottles it flagged) and false negatives fn (cracked bottles it missed). Write precision_recall_f1(tp, fp, fn) that returns the precision, recall and F1 score. On a quiet shift some of these counts are 0, and the function must still return numbers.

Change the shift’s counts

precision = tp / (tp + fp), recall = tp / (tp + fn)
tp: cracked and flaggedfp: good bottle flaggedfn: crack missed
tp8
fp2
fn4
Precision0.8Recall0.667F10.727

Precision 8 / (8 + 2) = 0.8. Recall 8 / (8 + 4) = 0.667. F1 = 2 × P × R / (P + R) = 0.727.

Precision 0.8, recall 0.667, F1 0.727.

Examples

Most flags are right, but a third of the cracks got through

precision_recall_f1(8, 2, 4)

returns (0.8, 0.666667, 0.727273)

Nothing flagged: precision has nothing to divide, so it is 0.0

precision_recall_f1(0, 0, 5)

returns (0, 0, 0)

Requirements

  • tp, fp and fn are ints of 0 or more.
  • Return a tuple (precision, recall, f1) of three floats.
  • Precision is tp / (tp + fp). Recall is tp / (tp + fn). F1 is 2 * precision * recall / (precision + recall).
  • When a denominator is 0, that value is 0.0. This covers precision with nothing flagged, recall with nothing cracked, and F1 when precision and recall are both 0.
The idea behind it

Precision and recall split a model's quality into two questions. Precision, tp / (tp + fp), is the share of flagged items that were really positive: how much a flag can be trusted. Recall, tp / (tp + fn), is the share of real positives that got flagged: how much the model catches. One can be raised at the cost of the other by moving the decision threshold. F1 combines them with the harmonic mean, 2pr / (p + r). The harmonic mean stays close to the lower of the two, so a model with precision 1.0 and recall 0.1 gets an F1 of about 0.18. The plain average would give 0.55. Real dashboards compute these on every batch, and some batches have no flags or no positives. Libraries such as scikit-learn report 0 in those cases, and so does this function.

pythonCtrl+Enter runs
import numpy as np

def precision_recall_f1(tp, fp, fn):
"""Precision, recall and F1 from confusion counts.

tp: int, cracked bottles the model flagged
fp: int, good bottles the model flagged
fn: int, cracked bottles the model missed
Returns (precision, recall, f1) as three floats. Any value whose
denominator is 0 is 0.0.
"""
raise NotImplementedError

Stuck? Reveal one rung at a time

Worked solution

Pro includes the solution and walkthrough for every problem, plus the hands-on labs. The first problem of each topic is free.