cbrkit.eval.retrieval

 1from collections.abc import Sequence
 2from typing import Any, Literal
 3
 4from ..helpers import normalize_and_scale, round, unpack_float
 5from ..retrieval import Result, ResultStep
 6from ..typing import EvalMetricFunc, Float, QueryCaseMatrix
 7from .common import DEFAULT_METRICS, compute
 8
 9
10def retrieval_step[Q, C, S: Float](
11    qrels: QueryCaseMatrix[Q, C, int],
12    step: ResultStep[Q, C, Any, S],
13    metrics: Sequence[str] = DEFAULT_METRICS,
14    metric_funcs: dict[str, EvalMetricFunc] | None = None,
15) -> dict[str, float]:
16    return compute(
17        qrels,
18        {query: entry.similarities for query, entry in step.queries.items()},
19        metrics,
20        metric_funcs,
21    )
22
23
24def retrieval[Q, C, S: Float](
25    qrels: QueryCaseMatrix[Q, C, int],
26    result: Result[Q, C, Any, S],
27    metrics: Sequence[str] = DEFAULT_METRICS,
28    metric_funcs: dict[str, EvalMetricFunc] | None = None,
29) -> list[dict[str, float]]:
30    return [
31        retrieval_step(
32            qrels,
33            step,
34            metrics,
35            metric_funcs,
36        )
37        for step in result.steps
38    ]
39
40
41def retrieval_step_to_qrels[Q, C, S: Float](
42    result: ResultStep[Q, C, Any, S],
43    max_qrel: int | None = None,
44    min_qrel: int = 1,
45    round_mode: Literal["floor", "ceil", "nearest"] = "nearest",
46    auto_scale: bool = True,
47) -> QueryCaseMatrix[Q, C, int]:
48    if max_qrel is None:
49        return {
50            query: {
51                case: rank
52                for rank, case in enumerate(reversed(entry.ranking), start=min_qrel)
53            }
54            for query, entry in result.queries.items()
55        }
56
57    sims = {
58        query: {case: unpack_float(value) for case, value in entry.similarities.items()}
59        for query, entry in result.queries.items()
60    }
61    if auto_scale:
62        min_sim = min(min(entries.values()) for entries in sims.values())
63        max_sim = max(max(entries.values()) for entries in sims.values())
64    else:
65        min_sim = 0.0
66        max_sim = 1.0
67
68    return {
69        query: {
70            case: round(
71                normalize_and_scale(sim, min_sim, max_sim, min_qrel, max_qrel),
72                round_mode,
73            )
74            for case, sim in entry.items()
75        }
76        for query, entry in sims.items()
77    }
78
79
80def retrieval_to_qrels[Q, C, S: Float](
81    result: Result[Q, C, Any, S],
82    max_qrel: int = 5,
83    min_qrel: int = 1,
84    round_mode: Literal["floor", "ceil", "nearest"] = "nearest",
85    auto_scale: bool = True,
86) -> list[QueryCaseMatrix[Q, C, int]]:
87    return [
88        retrieval_step_to_qrels(
89            step,
90            max_qrel,
91            min_qrel,
92            round_mode,
93            auto_scale,
94        )
95        for step in result.steps
96    ]
def retrieval_step( qrels: QueryCaseMatrix[Q, C, int], step: cbrkit.model.ResultStep[TypeVar, TypeVar, Any, TypeVar], metrics: Sequence[str] = ('precision', 'recall', 'f1', 'map', 'ndcg', 'correctness', 'completeness'), metric_funcs: dict[str, cbrkit.typing.EvalMetricFunc] | None = None) -> dict[str, float]:
11def retrieval_step[Q, C, S: Float](
12    qrels: QueryCaseMatrix[Q, C, int],
13    step: ResultStep[Q, C, Any, S],
14    metrics: Sequence[str] = DEFAULT_METRICS,
15    metric_funcs: dict[str, EvalMetricFunc] | None = None,
16) -> dict[str, float]:
17    return compute(
18        qrels,
19        {query: entry.similarities for query, entry in step.queries.items()},
20        metrics,
21        metric_funcs,
22    )
def retrieval( qrels: QueryCaseMatrix[Q, C, int], result: cbrkit.model.Result[TypeVar, TypeVar, Any, TypeVar], metrics: Sequence[str] = ('precision', 'recall', 'f1', 'map', 'ndcg', 'correctness', 'completeness'), metric_funcs: dict[str, cbrkit.typing.EvalMetricFunc] | None = None) -> list[dict[str, float]]:
25def retrieval[Q, C, S: Float](
26    qrels: QueryCaseMatrix[Q, C, int],
27    result: Result[Q, C, Any, S],
28    metrics: Sequence[str] = DEFAULT_METRICS,
29    metric_funcs: dict[str, EvalMetricFunc] | None = None,
30) -> list[dict[str, float]]:
31    return [
32        retrieval_step(
33            qrels,
34            step,
35            metrics,
36            metric_funcs,
37        )
38        for step in result.steps
39    ]
def retrieval_step_to_qrels( result: cbrkit.model.ResultStep[TypeVar, TypeVar, Any, TypeVar], max_qrel: int | None = None, min_qrel: int = 1, round_mode: Literal['floor', 'ceil', 'nearest'] = 'nearest', auto_scale: bool = True) -> QueryCaseMatrix[Q, C, int]:
42def retrieval_step_to_qrels[Q, C, S: Float](
43    result: ResultStep[Q, C, Any, S],
44    max_qrel: int | None = None,
45    min_qrel: int = 1,
46    round_mode: Literal["floor", "ceil", "nearest"] = "nearest",
47    auto_scale: bool = True,
48) -> QueryCaseMatrix[Q, C, int]:
49    if max_qrel is None:
50        return {
51            query: {
52                case: rank
53                for rank, case in enumerate(reversed(entry.ranking), start=min_qrel)
54            }
55            for query, entry in result.queries.items()
56        }
57
58    sims = {
59        query: {case: unpack_float(value) for case, value in entry.similarities.items()}
60        for query, entry in result.queries.items()
61    }
62    if auto_scale:
63        min_sim = min(min(entries.values()) for entries in sims.values())
64        max_sim = max(max(entries.values()) for entries in sims.values())
65    else:
66        min_sim = 0.0
67        max_sim = 1.0
68
69    return {
70        query: {
71            case: round(
72                normalize_and_scale(sim, min_sim, max_sim, min_qrel, max_qrel),
73                round_mode,
74            )
75            for case, sim in entry.items()
76        }
77        for query, entry in sims.items()
78    }
def retrieval_to_qrels( result: cbrkit.model.Result[TypeVar, TypeVar, Any, TypeVar], max_qrel: int = 5, min_qrel: int = 1, round_mode: Literal['floor', 'ceil', 'nearest'] = 'nearest', auto_scale: bool = True) -> list[QueryCaseMatrix[Q, C, int]]:
81def retrieval_to_qrels[Q, C, S: Float](
82    result: Result[Q, C, Any, S],
83    max_qrel: int = 5,
84    min_qrel: int = 1,
85    round_mode: Literal["floor", "ceil", "nearest"] = "nearest",
86    auto_scale: bool = True,
87) -> list[QueryCaseMatrix[Q, C, int]]:
88    return [
89        retrieval_step_to_qrels(
90            step,
91            max_qrel,
92            min_qrel,
93            round_mode,
94            auto_scale,
95        )
96        for step in result.steps
97    ]