Commit c89e5cb3 by Amir MOHAMMADI

Merge branch 'roc-for-far' into 'master'

recompute far values in roc_for_far

Closes #27

See merge request !48
parents d692bc9b 4f094765
Pipeline #18297 passed with stages
in 58 minutes 40 seconds
......@@ -421,73 +421,21 @@ bob::measure::roc_for_far(const blitz::Array<double, 1> &negatives,
sort(negatives, neg, is_sorted);
sort(positives, pos, is_sorted);
// do some magic to compute the FRR list
blitz::Array<double, 2> retval(2, n_points);
// index into the FAR and FRR list
// index into the FAR list
int far_index = n_points - 1;
int pos_index = 0, neg_index = 0;
int n_pos = pos.extent(0), n_neg = neg.extent(0);
// iterators into the result lists
auto pos_it = pos.begin(), neg_it = neg.begin();
// do some fast magic to compute the FRR values ;-)
do {
// check whether the current positive value is less than the current
// negative one
if (*pos_it < *neg_it) {
// increase the positive count
++pos_index;
// go to the next positive value
++pos_it;
} else {
// increase the negative count
++neg_index;
// go to the next negative value
++neg_it;
}
// check, if we have reached a new FAR limit,
// i.e. if the relative number of negative similarities is greater than
// 1-FAR (which is the CRR)
if (((double)neg_index / (double)n_neg > 1. - far_list(far_index)) &&
!(bob::core::isClose((double)neg_index / (double)n_neg,
1. - far_list(far_index), 1e-9, 1e-9))) {
// copy the far value
retval(0, far_index) = far_list(far_index);
// calculate the FRR for the current FAR
retval(1, far_index) = (double)pos_index / (double)n_pos;
// go to the next FAR value
--far_index;
}
// do this, as long as there are elements in both lists left and not all FRR
// elements where calculated yet
} while (pos_it != pos.end() && neg_it != neg.end() && far_index >= 0);
// check if all FRR values have been set
if (far_index >= 0) {
// walk to the end of both lists; at least one of both lists should already
// have reached its limit.
while (pos_it != pos.end() && pos_it++ != pos.end())
++pos_index;
while (neg_it != neg.end() && neg_it++ != neg.end())
++neg_index;
// fill in the remaining elements of the CAR list
do {
// copy the FAR value
retval(0, far_index) = far_list(far_index);
// check if the criterion is fulfilled (should be, as long as the lowest
// far is not below 0)
if ((double)neg_index / (double)n_neg > 1. - far_list(far_index)) {
// calculate the FRR for the current FAR
retval(1, far_index) = (double)pos_index / (double)n_pos;
} else {
// set FRR to 1 (this should never happen, but might be due to numerical
// issues)
retval(1, far_index) = 1.;
}
} while (far_index--);
// Get the threshold for the requested far values and calculate far and frr
// values based on the threshold.
while(far_index >= 0) {
// calculate the threshold for the requested far
auto threshold = bob::measure::farThreshold(neg, pos, far_list(far_index), true);
// calculate the frr and re-calculate the far
auto farfrr = bob::measure::farfrr(neg, pos, threshold);
retval(0, far_index) = farfrr.first;
retval(1, far_index) = farfrr.second;
far_index--;
}
return retval;
......
......@@ -714,11 +714,7 @@ static auto far_threshold_doc =
bob::extension::FunctionDoc(
"far_threshold", "Computes the threshold such that the real FAR is "
"**at most** the requested ``far_value`` if possible",
"If no such threshold can be computed, ``NaN`` is returned. It is "
"impossible to compute the threshold, when too few non-identical "
"highest scores exist, so that the desired ``far_value`` cannot be "
"reached by any threshold.\n\n"
".. note::\n\n"
"\n\n.. note::\n\n"
" The scores will be sorted internally, requiring the scores to be "
"copied.\n"
" To avoid this copy, you can sort the ``negatives`` scores "
......@@ -774,11 +770,7 @@ static auto frr_threshold_doc =
bob::extension::FunctionDoc(
"frr_threshold", "Computes the threshold such that the real FRR is "
"**at most** the requested ``frr_value`` if possible",
"If no such threshold can be computed, ``NaN`` is returned. It is "
"impossible to compute the threshold, when too few non-identical "
"lowest scores exist, so that the desired ``frr_value`` cannot be "
"reached by any threshold.\n\n"
".. note::\n\n"
"\n\n.. note::\n\n"
" The scores will be sorted internally, requiring the scores to be "
"copied.\n"
" To avoid this copy, you can sort the ``positives`` scores "
......
......@@ -293,17 +293,18 @@ def test_plots():
assert numpy.array_equal(xy, xyref)
# This example will test the ROC for FAR plot calculation functionality.
far = [0.01, 0.1, 1]
ref = [0.42, 0.12, 0]
xy = roc_for_far(negatives, positives, far)
requested_far = [0.01, 0.1, 1]
expected_far = [0.0, 0.1, 1]
expected_frr = [0.48, 0.12, 0]
xy = roc_for_far(negatives, positives, requested_far)
assert numpy.array_equal(xy[0], far)
assert numpy.array_equal(xy[1], ref)
assert numpy.array_equal(xy[0], expected_far), xy[0]
assert numpy.array_equal(xy[1], expected_frr), xy[1]
# This example will test the Precision-Recall plot calculation functionality.
xy = precision_recall_curve(negatives, positives, 100)
# uncomment the next line to save a reference value
# save('nonsep-roc.hdf5', xy)
# save('nonsep-precisionrecall.hdf5', xy)
xyref = bob.io.base.load(F('nonsep-precisionrecall.hdf5'))
assert numpy.array_equal(xy, xyref)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment