Commit 0af00f10 authored by Amir MOHAMMADI's avatar Amir MOHAMMADI

Merge branch 'title' into 'master'

Title and histograms subplots

See merge request !61
parents 40a7e636 db43e6a0
Pipeline #19892 passed with stages
in 36 minutes and 41 seconds
......@@ -10,6 +10,7 @@ import numpy
LOGGER = logging.getLogger('bob.measure')
def split(filename):
"""split(filename) -> negatives, positives
......@@ -36,7 +37,7 @@ def split(filename):
columns = numpy.loadtxt(filename)
neg_pos = columns[:, 0]
scores = columns[:, 1]
except:
except Exception:
LOGGER.error('''Cannot read {}. This file must be a two columns file with
the first column containing -1 or 1 (i.e. negative or
positive) and the second the scores
......@@ -45,6 +46,7 @@ def split(filename):
return (scores[numpy.where(neg_pos == -1)],
scores[numpy.where(neg_pos == 1)])
def split_files(filenames):
"""split_files
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
"""Generate random scores.
"""
import pkg_resources # to make sure bob gets imported properly
import os
import logging
import numpy
......@@ -15,6 +14,7 @@ logger = logging.getLogger(__name__)
NUM_NEG = 5000
NUM_POS = 5000
def gen_score_distr(mean_neg, mean_pos, sigma_neg=1, sigma_pos=1):
"""Generate scores from normal distributions
......@@ -47,17 +47,17 @@ def gen_score_distr(mean_neg, mean_pos, sigma_neg=1, sigma_pos=1):
return neg_scores, pos_scores
def write_scores_to_file(pos, neg, filename):
def write_scores_to_file(neg, pos, filename):
"""Writes score distributions into 2-column score files. For the format of
the 2-column score files, please refer to Bob's documentation. See
:py:func:`bob.measure.load.split`.
Parameters
----------
pos : :py:class:`numpy.ndarray`
Scores for positive samples.
neg : :py:class:`numpy.ndarray`
Scores for negative samples.
pos : :py:class:`numpy.ndarray`
Scores for positive samples.
filename : str
The path to write the score to.
"""
......@@ -72,6 +72,7 @@ def write_scores_to_file(pos, neg, filename):
text = '-1 %f\n' % i if nan_dist(mt) > 0.01 else '1 nan\n'
f.write(text)
@click.command()
@click.argument('outdir')
@click.option('--mean-neg', default=-1, type=FLOAT, show_default=True)
......
......@@ -30,7 +30,7 @@ def test_metrics():
assert result.exit_code == 0
with runner.isolated_filesystem():
result = runner.invoke(
commands.metrics, ['-l', 'tmp', dev1, test1, dev2, test2, '-Z',
commands.metrics, ['-l', 'tmp', dev1, test1, dev2, test2, '-lg',
'A,B']
)
assert result.exit_code == 0, (result.exit_code, result.output)
......@@ -84,6 +84,7 @@ def test_det():
with runner.isolated_filesystem():
result = runner.invoke(commands.det, ['--split', '--output',
'test.pdf', '--legends', 'A,B',
'-lc', 'upper-right',
dev1, test1, dev2, test2])
if result.output:
click.echo(result.output)
......@@ -112,6 +113,7 @@ def test_epc():
with runner.isolated_filesystem():
result = runner.invoke(commands.epc, ['--output', 'test.pdf',
'--legends', 'A,B',
'-lc', 'upper-right',
dev1, test1, dev2, test2])
if result.output:
click.echo(result.output)
......@@ -130,7 +132,8 @@ def test_hist():
assert result.exit_code == 0, (result.exit_code, result.output)
with runner.isolated_filesystem():
result = runner.invoke(commands.hist, ['--no-evaluation', '--criterion', 'hter',
result = runner.invoke(commands.hist, ['--no-evaluation', '--criterion',
'min-hter',
'--output', 'HISTO.pdf', '-b',
'30,100', dev1, dev2])
if result.output:
......@@ -140,6 +143,7 @@ def test_hist():
with runner.isolated_filesystem():
result = runner.invoke(commands.hist, ['--criterion', 'eer','--output',
'HISTO.pdf', '-b', '30,20',
'-sp', 221,
dev1, test1, dev2, test2])
if result.output:
click.echo(result.output)
......@@ -158,8 +162,8 @@ def test_evaluate():
with runner.isolated_filesystem():
result = runner.invoke(
commands.evaluate, ['--no-evaluation', '--output', 'my_plots.pdf', '-b',
'30,69', '-n', 300, dev1, dev2])
commands.evaluate, ['--no-evaluation', '--output', 'my_plots.pdf',
'-n', 300, dev1, dev2])
assert result.exit_code == 0, (result.exit_code, result.output)
with runner.isolated_filesystem():
......
......@@ -4,6 +4,7 @@ import numpy
import scipy.stats
import bob.core
def remove_nan(scores):
"""remove_nan
......@@ -28,6 +29,7 @@ def remove_nan(scores):
logger.warning('Found {} NaNs in {} scores'.format(sum_nans, total))
return scores[numpy.where(~nans)], sum_nans, total
def get_fta(scores):
"""get_fta
calculates the Failure To Acquire (FtA) rate, i.e. proportion of NaN(s)
......@@ -53,6 +55,7 @@ def get_fta(scores):
fta_total += total
return ((neg, pos), fta_sum / fta_total)
def get_fta_list(scores):
""" Get FTAs for a list of scores
......@@ -84,13 +87,14 @@ def get_fta_list(scores):
fta_list.append(fta)
return (neg_list, pos_list, fta_list)
def get_thres(criter, neg, pos, far=None):
"""Get threshold for the given positive/negatives scores and criterion
Parameters
----------
criter :
Criterion (`eer` or `hter`)
Criterion (`eer` or `hter` or `far`)
neg : :py:class:`numpy.ndarray`:
array of negative scores
pos : :py:class:`numpy.ndarray`::
......@@ -104,7 +108,7 @@ def get_thres(criter, neg, pos, far=None):
if criter == 'eer':
from . import eer_threshold
return eer_threshold(neg, pos)
elif criter == 'hter':
elif criter == 'min-hter':
from . import min_hter_threshold
return min_hter_threshold(neg, pos)
elif criter == 'far':
......@@ -116,6 +120,7 @@ def get_thres(criter, neg, pos, far=None):
else:
raise ValueError("Incorrect plotting criterion: ``%s``" % criter)
def get_colors(n):
"""get_colors
Get a list of matplotlib colors
......@@ -135,7 +140,8 @@ def get_colors(n):
cmap = pyplot.cm.get_cmap(name='magma')
return [cmap(i) for i in numpy.linspace(0, 1.0, n + 1)]
return ['C0','C1','C2','C3','C4','C5','C6','C7','C8','C9']
return ['C0', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9']
def get_linestyles(n, on=True):
"""Get a list of matplotlib linestyles
......@@ -154,24 +160,25 @@ def get_linestyles(n, on=True):
return [None] * n
list_linestyles = [
(0, ()), #solid
(0, (1, 1)), #densely dotted
(0, (5, 5)), #dashed
(0, (5, 1)), #densely dashed
(0, (3, 1, 1, 1, 1, 1)), #densely dashdotdotted
(0, (3, 10, 1, 10, 1, 10)), #loosely dashdotdotted
(0, (3, 5, 1, 5, 1, 5)), #dashdotdotted
(0, (3, 1, 1, 1)), #densely dashdotted
(0, (1, 5)), #dotted
(0, (3, 5, 1, 5)), #dashdotted
(0, (5, 10)), #loosely dashed
(0, (3, 10, 1, 10)), #loosely dashdotted
(0, (1, 10)) #loosely dotted
(0, ()), # solid
(0, (1, 1)), # densely dotted
(0, (5, 5)), # dashed
(0, (5, 1)), # densely dashed
(0, (3, 1, 1, 1, 1, 1)), # densely dashdotdotted
(0, (3, 10, 1, 10, 1, 10)), # loosely dashdotdotted
(0, (3, 5, 1, 5, 1, 5)), # dashdotdotted
(0, (3, 1, 1, 1)), # densely dashdotted
(0, (1, 5)), # dotted
(0, (3, 5, 1, 5)), # dashdotted
(0, (5, 10)), # loosely dashed
(0, (3, 10, 1, 10)), # loosely dashdotted
(0, (1, 10)) # loosely dotted
]
while n > len(list_linestyles):
list_linestyles += list_linestyles
return list_linestyles
def confidence_for_indicator_variable(x, n, alpha=0.05):
'''Calculates the confidence interval for proportion estimates
The Clopper-Pearson interval method is used for estimating the confidence
......
......@@ -100,11 +100,11 @@ defined in the first equation.
The input to create these two vectors is generated by experiments conducted
by the user and normally sits in files that may need some parsing before
these vectors can be extracted. While it is not possible to provide a parser
these vectors can be extracted. While it is not possible to provide a parser
for every individual file that may be generated in different experimental
frameworks, we do provide a parser for a generic two columns format
where the first column contains -1/1 for negative/positive and the second column
contains score values. Please refer to the documentation of
contains score values. Please refer to the documentation of
:py:func:`bob.measure.load.split` for more details.
In the remainder of this section we assume you have successfully parsed and
......@@ -220,18 +220,18 @@ of the true value being within the interval estimate is equal to :math:`\alpha`.
For example, a 95% confidence interval (i.e. :math:`\alpha = 0.95`) for a
parameter :math:`x` is given by :math:`[L, U]` such that
.. math:: Prob(x∈[L,U]) = 95%
.. math:: Prob(x∈[L,U]) = 95%
The smaller the test size, the wider the confidence
The smaller the test size, the wider the confidence
interval will be, and the greater :math:`\alpha`, the smaller the confidence interval
will be.
`The Clopper-Pearson interval`_, a common method for calculating
confidence intervals, is function of the number of success, the number of trials
confidence intervals, is function of the number of success, the number of trials
and confidence
value :math:`\alpha` is used as :py:func:`bob.measure.utils.confidence_for_indicator_variable`.
It is based on the cumulative probabilities of the binomial distribution. This
method is quite conservative, meaning that the true coverage rate of a 95%
method is quite conservative, meaning that the true coverage rate of a 95%
Clopper–Pearson interval may be well above 95%.
For example, we want to evaluate the reliability of a system to
......@@ -470,6 +470,8 @@ look at the implementations at :py:mod:`bob.measure.plot` to understand how to
use the |project| methods to compute the curves and interlace that in the way
that best suits you.
.. _bob.measure.command_line:
Full applications
-----------------
......@@ -549,7 +551,7 @@ on an evaluation set:
.. note::
Table format can be changed using ``--tablefmt`` option, the default format
being ``rst``. Please refer to ``bob measure metrics --help`` for more details.
Plots
=====
......@@ -573,7 +575,7 @@ For example, to generate a DET curve from development and evaluation datasets:
.. code-block:: sh
$bob measure det --output 'my_det.pdf' dev-1.txt eval-1.txt
$bob measure det -v --output 'my_det.pdf' dev-1.txt eval-1.txt
dev-2.txt eval-2.txt
where `my_det.pdf` will contain DET plots for the two experiments.
......@@ -583,18 +585,22 @@ where `my_det.pdf` will contain DET plots for the two experiments.
different plots. You can force gather everything in the same plot using
``--no-split`` option.
.. note::
The ``--figsize`` and ``--style`` options are two powerful options that can
dramatically change the appearance of your figures. Try them! (e.g.
``--figsize 12,10 --style grayscale``)
Evaluate
========
A convenient command ``evaluate`` is provided to generate multiple metrics and
plots for a list of experiments. It generates two ``metrics`` outputs with ERR
and HTER criteria along with ``roc``, ``det``, ``epc``, ``hist`` plots for each
and min-HTER criteria along with ``roc``, ``det``, ``epc``, ``hist`` plots for each
experiment. For example:
.. code-block:: sh
$bob measure evaluate -l 'my_metrics.txt' -o 'my_plots.pdf' {sys1, sys2}/
{eval,dev}
$bob measure evaluate -v -l 'my_metrics.txt' -o 'my_plots.pdf' {sys1,sys2}/{dev,eval}
will output metrics and plots for the two experiments (dev and eval pairs) in
`my_metrics.txt` and `my_plots.pdf`, respectively.
......
......@@ -126,7 +126,6 @@ CLI options
bob.measure.script.common_options.eval_option
bob.measure.script.common_options.sep_dev_eval_option
bob.measure.script.common_options.cmc_option
bob.measure.script.common_options.show_dev_option
bob.measure.script.common_options.print_filenames_option
bob.measure.script.common_options.const_layout_option
bob.measure.script.common_options.axes_val_option
......@@ -151,6 +150,9 @@ CLI options
bob.measure.script.common_options.x_label_option
bob.measure.script.common_options.y_label_option
bob.measure.script.common_options.style_option
bob.measure.script.common_options.subplot_option
bob.measure.script.common_options.legend_ncols_option
bob.measure.script.common_options.no_legend_option
Details
-------
......
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