Before you start
Two overlap scores for binary masks, the standard metrics for segmentation.
Jaccard (IoU) = |A and B| / |A or B|
Dice (F1) = 2 * |A and B| / (|A| + |B|)
y_true and y_pred are arrays of the same shape containing 0 and 1, and
may be multidimensional (a 2-D image mask, for instance). Flatten them and treat
every element as one pixel.
Both range over [0, 1] and agree at 0 and 1, but Dice is always the more
generous of the two in between, since it counts the intersection twice. Dice on
binary masks is exactly the F1 score with pixels as samples.
If both masks are empty, define both scores as 1.0: the prediction of "nothing
here" was correct.
Return (jaccard, dice).
def jaccard_dice(y_true, y_pred):
Input
y_true = np.array([1, 1, 0, 0])
y_pred = np.array([1, 0, 1, 0])
jaccard_dice(y_true, y_pred)
Output
(0.3333333333333333, 0.5)
Reasoning
Only the first pixel is in both masks, so the intersection is 1. The union is 3, so Jaccard is 1/3. Each mask has two pixels, so Dice is 2 * 1 / (2 + 2) = 0.5.
1.0.Check runs the visible cases against a fresh kernel. Submit runs the hidden ones too.
⇧↵run cell