Coverage for src/bob/measure/calibration.py: 12%
42 statements
« prev ^ index » next coverage.py v7.0.5, created at 2023-06-16 14:10 +0200
« prev ^ index » next coverage.py v7.0.5, created at 2023-06-16 14:10 +0200
1#!/usr/bin/env python
2# vim: set fileencoding=utf-8 :
3# Thu May 16 11:41:49 CEST 2013
5"""Measures for calibration"""
7import math
9import numpy
12def cllr(negatives, positives):
13 """Cost of log likelihood ratio as defined by the Bosaris toolkit
15 Computes the 'cost of log likelihood ratio' (:math:`C_{llr}`) measure as
16 given in the Bosaris toolkit
19 Parameters:
21 negatives (array): 1D float array that contains the scores of the
22 "negative" (noise, non-class) samples of your classifier.
24 positives (array): 1D float array that contains the scores of the
25 "positive" (signal, class) samples of your classifier.
28 Returns:
30 float: The computed :math:`C_{llr}` value.
32 """
33 sum_pos, sum_neg = 0.0, 0.0
34 for pos in positives:
35 sum_pos += math.log(1.0 + math.exp(-pos), 2.0)
36 for neg in negatives:
37 sum_neg += math.log(1.0 + math.exp(neg), 2.0)
38 return (sum_pos / len(positives) + sum_neg / len(negatives)) / 2.0
41def min_cllr(negatives, positives):
42 """Minimum cost of log likelihood ratio as defined by the Bosaris toolkit
44 Computes the 'minimum cost of log likelihood ratio' (:math:`C_{llr}^{min}`)
45 measure as given in the bosaris toolkit
48 Parameters:
50 negatives (array): 1D float array that contains the scores of the
51 "negative" (noise, non-class) samples of your classifier.
53 positives (array): 1D float array that contains the scores of the
54 "positive" (signal, class) samples of your classifier.
57 Returns:
59 float: The computed :math:`C_{llr}^{min}` value.
61 """
63 # first, sort both scores
64 neg = sorted(negatives)
65 pos = sorted(positives)
66 N = len(neg)
67 P = len(pos)
68 II = N + P
69 # now, iterate through both score sets and add a 0 for negative and 1 for
70 # positive scores
71 n, p = 0, 0
72 ideal = numpy.zeros(II)
73 neg_indices = [0] * N
74 pos_indices = [0] * P
75 for i in range(II):
76 if p < P and (n == N or neg[n] > pos[p]):
77 pos_indices[p] = i
78 p += 1
79 ideal[i] = 1
80 else:
81 neg_indices[n] = i
82 n += 1
84 # compute the pool adjacent violaters method on the ideal LLR scores
85 ghat = numpy.ndarray(ideal.shape, dtype=numpy.float)
86 raise NotImplementedError("No pavx implementation")
87 pavx(ideal, ghat) # noqa: F821
89 # disable runtime warnings for a short time since log(0) will raise a warning
90 old_warn_setup = numpy.seterr(divide="ignore")
91 # ... compute logs
92 posterior_log_odds = numpy.log(ghat) - numpy.log(1.0 - ghat)
93 log_prior_odds = math.log(float(P) / float(N))
94 # ... activate old warnings
95 numpy.seterr(**old_warn_setup)
97 llrs = posterior_log_odds - log_prior_odds
99 # some weired addition
100 # for i in range(II):
101 # llrs[i] += float(i)*1e-6/float(II)
103 # unmix positive and negative scores
104 new_neg = numpy.zeros(N)
105 for n in range(N):
106 new_neg[n] = llrs[neg_indices[n]]
107 new_pos = numpy.zeros(P)
108 for p in range(P):
109 new_pos[p] = llrs[pos_indices[p]]
111 # compute cllr of these new 'optimal' LLR scores
112 return cllr(new_neg, new_pos)