PY-88
Calculate Retrieval Measures at Fixed Cutoffs
Task
Write retrieval_measures_at_cutoffs(ranked_ids, relevant_ids, cutoffs).
ranked_ids is an ordered list of retrieved document IDs; duplicate retrieved
IDs are allowed. relevant_ids is a list of unique IDs judged relevant for
this query. cutoffs is a list of unique positive integers, and its order is
the order of the returned records.
For each cutoff k, inspect the first min(k, len(ranked_ids)) retrieved
positions. The number of hits is the number of distinct IDs in that prefix
that occur in relevant_ids: a duplicate occupies another retrieved position
but earns no second relevance hit. Missing relevant IDs remain in the recall
denominator. Use these exact formulas:
precision = hits / retrieved_positions (0.0 when the denominator is 0)
recall = hits / len(relevant_ids) (0.0 when there are no relevant IDs)
f1 = 2 * precision * recall / (precision + recall)
(0.0 when precision + recall is 0)
Return a list of dictionaries in the supplied cutoff order. Each dictionary
has exactly "cutoff", "retrieved", "hits", "precision", "recall",
and "f1"; retrieved is the number of prefix positions, including
duplicates. All three measures are Python floats. Raise
ValueError("relevant IDs must be unique") for a repeated relevant ID,
ValueError("cutoffs must be positive and unique") for a non-positive or
repeated cutoff, and keep every input unchanged.
Example
For ranked IDs ['d1','d2','d1','d3'], relevant IDs ['d1','d3'], and cutoffs
[1,3,5], the records have (retrieved, hits) of (1,1), (3,1), and
(4,2). The duplicate d1 at position three increases the precision
denominator but not the hit count. The cutoff 5 simply uses all four
available positions.
If relevant_ids is empty, every recall and F1 value is 0.0; if a cutoff
prefix is empty, its precision is 0.0 as well.
Your implementation
No retrieval library or ranking theory is required. Do not print or ask for input.