ranklens.core¶
ranklens.core
¶
Project vocabulary: types and errors. Depends on the standard library only.
Qrels
module-attribute
¶
Qrels: TypeAlias = dict[QueryId, dict[DocId, float]]
Graded relevance judgements: qrels[query_id][doc_id] -> relevance.
SegmentKey
module-attribute
¶
SegmentKey: TypeAlias = tuple[str, ...]
Segment field values in a fixed order, e.g. ("mobile", "ru").
ConfigError
¶
Bases: RankLensError
Invalid configuration: metric names, parameters, plugins.
Source code in src/ranklens/core/exceptions.py
162 163 | |
DataError
¶
Bases: RankLensError
Input data is malformed or violates an input contract.
Source code in src/ranklens/core/exceptions.py
58 59 | |
DegenerateWeightsWarning
¶
Bases: RankLensWarning
A few importance weights dominate an off-policy estimate.
Source code in src/ranklens/core/exceptions.py
301 302 | |
DuplicateDocumentError
¶
Bases: DataError
The same document appears twice in one ranked list.
Source code in src/ranklens/core/exceptions.py
136 137 138 139 140 141 142 143 144 145 | |
DuplicateMetricError
¶
Bases: ConfigError
A metric with this name is already registered.
Source code in src/ranklens/core/exceptions.py
196 197 198 199 200 201 202 203 204 205 206 207 | |
InsufficientSampleError
¶
Bases: StatisticalError
Too few observations (queries, impressions) for the requested procedure.
Source code in src/ranklens/core/exceptions.py
274 275 276 277 278 279 280 281 282 283 284 285 286 287 | |
MalformedRowError
¶
Bases: DataError
A row cannot be parsed according to the schema.
Source code in src/ranklens/core/exceptions.py
62 63 64 65 66 67 68 69 70 71 72 73 | |
MetricNotFoundError
¶
Bases: ConfigError
Requested metric is not registered.
Source code in src/ranklens/core/exceptions.py
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | |
MetricSpecError
¶
Bases: ConfigError
A metric spec cannot be parsed or has invalid parameters.
Source code in src/ranklens/core/exceptions.py
184 185 186 187 188 189 190 191 192 193 | |
MissingColumnError
¶
Bases: DataError
A required column is absent from the input.
Source code in src/ranklens/core/exceptions.py
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | |
MissingDependencyError
¶
Bases: ConfigError
An optional dependency required by a feature is not installed.
Source code in src/ranklens/core/exceptions.py
227 228 229 230 231 232 233 234 235 236 237 238 239 240 | |
MissingQrelsError
¶
Bases: DataError
A query has no relevance judgements.
Source code in src/ranklens/core/exceptions.py
148 149 150 151 152 153 154 155 156 | |
ModelError
¶
Bases: RankLensError
A model cannot be used for scoring or explanation.
Source code in src/ranklens/core/exceptions.py
246 247 | |
PluginWarning
¶
Bases: RankLensWarning
A third-party plugin could not be loaded and was skipped.
Source code in src/ranklens/core/exceptions.py
305 306 | |
RankLensError
¶
Bases: Exception
Base class for all errors raised by ranklens.
Source code in src/ranklens/core/exceptions.py
51 52 | |
RankLensWarning
¶
Bases: UserWarning
Base class for all warnings emitted by ranklens.
Source code in src/ranklens/core/exceptions.py
293 294 | |
SkippedRowsWarning
¶
Bases: RankLensWarning
Invalid input rows were skipped in non-strict mode.
Source code in src/ranklens/core/exceptions.py
297 298 | |
SmallSampleWarning
¶
Bases: RankLensWarning
The sample is large enough to compute a number, but too small to trust it.
Source code in src/ranklens/core/exceptions.py
309 310 | |
StatisticalError
¶
Bases: RankLensError
A statistical procedure cannot produce a meaningful result.
Source code in src/ranklens/core/exceptions.py
270 271 | |
UngroupedInputError
¶
Bases: DataError
Rows of one query (or one logged impression) are not contiguous.
Source code in src/ranklens/core/exceptions.py
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | |
UnsortedInputError
¶
Bases: DataError
Rows are not sorted by query_id.
Source code in src/ranklens/core/exceptions.py
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | |
UnsupportedFormatError
¶
Bases: ConfigError
The input format cannot be determined or is not supported.
Source code in src/ranklens/core/exceptions.py
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 | |
UnsupportedModelError
¶
Bases: ModelError
No adapter exists for this model type.
Source code in src/ranklens/core/exceptions.py
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 | |
FeedbackScale
dataclass
¶
Ordered feedback events and their rewards, weakest first.
FeedbackScale.of({"click": 1, "cart": 3, "purchase": 10}): a document shown
without any event gets 0; a stronger event must not be worth less than a weaker one,
otherwise the order of the scale would mean nothing.
Source code in src/ranklens/core/feedback.py
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | |
of
classmethod
¶
of(rewards: Mapping[str, float]) -> FeedbackScale
Scale from a mapping in the order of its keys, weakest first.
Source code in src/ranklens/core/feedback.py
51 52 53 54 | |
reward
¶
reward(event: str) -> float
Reward of event; an empty event (shown, nothing happened) is 0.
Source code in src/ranklens/core/feedback.py
60 61 62 63 64 65 66 67 | |
Impression
dataclass
¶
One showing of a ranking by the logging policy and the feedback it got.
docs[i] was shown at 1-based positions[i] and earned rewards[i].
Positions ascend but may have gaps: a log may keep only the documents with
feedback, and the position is what the propensity of examination depends on.
Source code in src/ranklens/core/feedback.py
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | |
Metric
¶
Bases: Protocol
Value of one ranking against the judgements of its query.
Any callable with this signature is a metric, including a plain function.
k is the cutoff (None means the whole ranking). The display name comes
from the spec the metric was resolved from, not from the metric itself.
Source code in src/ranklens/core/protocols.py
11 12 13 14 15 16 17 18 19 20 21 | |
BootstrapInterval
dataclass
¶
Percentile bootstrap interval for the mean difference between two runs.
delta is the observed mean of per-query differences (b - a); low and high
bound it with confidence 1 - alpha. seed and n_resamples are kept so that
the number in a report can be reproduced exactly.
Source code in src/ranklens/core/result.py
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | |
excludes_zero
property
¶
excludes_zero: bool
Whether the interval lies entirely on one side of zero.
ComparisonResult
dataclass
¶
Comparison of one metric between two runs, A (baseline) and B.
Scope: one metric at one cutoff, averaged over the queries both runs measured. It does not say whether the runs order documents differently (same metric value, different order is entirely possible), only whether this metric differs.
delta is the mean of per-query differences B - A; ci_low/ci_high are its
bootstrap interval and p_value comes from the permutation test — the bootstrap
gives an interval, not a p-value, so the two are computed separately and both are
reported. q_value is filled in after correcting for multiple comparisons.
Source code in src/ranklens/core/result.py
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | |
significant
property
¶
significant: bool
Whether the difference passes alpha; after correction, by q_value.
ErrorSummary
dataclass
¶
Snapshot of data errors skipped while reading in non-strict mode.
Source code in src/ranklens/core/result.py
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | |
Evaluation
dataclass
¶
Metrics of one run and what happened to its queries.
n_queries: evaluated queries (in the run and in the qrels);n_without_relevant: evaluated queries without a positive grade — every metric scores 0 for them (mapandmrralso score 0 when no grade reachesrel);n_unjudged: queries of the run absent from the qrels — skipped, as in trec_eval;n_not_retrieved: queries of the qrels absent from the run — ignored, as in trec_eval.
segments carries the segment values of the evaluated queries, in the order of the
schema fields, so that the same evaluation can later be sliced without reading the run
again. It is empty when the run has no segment columns.
Source code in src/ranklens/core/result.py
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | |
ListwiseAttribution
dataclass
¶
How much a metric drops when a feature (or a group of them) stops carrying signal.
For each feature the values of the documents of a query are shuffled among them,
the documents are ranked again, and the drop of the metric is recorded per query:
drops[i] is a MetricResult of the drop for features[i], so the usual
statistics (compare, bootstrap) apply to it. baseline is the metric itself.
Source code in src/ranklens/core/result.py
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 | |
ranked
¶
ranked() -> tuple[tuple[str, float], ...]
(feature, mean drop over queries), the largest drop first.
Source code in src/ranklens/core/result.py
291 292 293 294 | |
MetricResult
dataclass
¶
Values of one metric: per query and their mean.
per_query is a read-only mapping (types.MappingProxyType): results are
shared between statistics and reports and must not be changed by either. Any other
mapping is copied on construction, so changing it later does not change the result.
Source code in src/ranklens/core/result.py
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | |
OffPolicyEstimate
dataclass
¶
Value of a new policy estimated from a log collected under an old one.
estimator is "ips" (expected discounted reward, unbiased under PBM) or
"snips" (its ratio to the reward of everything shown — a different quantity
with lower variance, see docs/math/offpolicy). The interval is a normal
approximation over impressions. n_clipped counts rewarded documents whose
weight hit clip; n_skipped counts impressions of queries the policy lacks.
ess is the effective sample size of the weights 1/p of the rewarded documents,
(Σw)² / Σw²: equal to n_rewarded when all weights are equal, far below it when
a few weights dominate.
Source code in src/ranklens/core/result.py
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | |
PairAttribution
dataclass
¶
Why a model scores document B above (or below) document A, feature by feature.
contributions[i] is the Shapley value of feature feature_names[i] in going
from A's features to B's: they add up to score_b - score_a exactly. method
is "exact" (all subsets) or "sampled" (n_permutations random orders).
Source code in src/ranklens/core/result.py
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 | |
ranked
¶
ranked() -> tuple[tuple[str, float], ...]
(feature, contribution) by absolute contribution, largest first.
Source code in src/ranklens/core/result.py
268 269 270 271 | |
PPIComparison
dataclass
¶
Comparison of two runs on cheap (proxy) judgements corrected by a gold sample.
Prediction-powered inference: the difference measured with proxy judgements on
every query, plus a correction measured on a random sample of queries that also
have gold judgements. lam weighs the proxy part (0 — gold only, 1 — classic
PPI); by default it is chosen from the data to minimize the variance (PPI++).
The interval and the p-value are normal approximations; q_value is filled in
after correcting for multiple comparisons, as in ComparisonResult.
Source code in src/ranklens/core/result.py
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 | |
significant
property
¶
significant: bool
Whether the difference passes alpha; after correction, by q_value.
QueryDiagnosis
dataclass
¶
A query where the model does badly, and which features move its metric.
causes are (feature, drop of the metric when the feature is shuffled), largest
absolute drop first. A positive drop: the feature helps here. A negative one:
shuffling it improves the ranking — the model trusts a feature that misleads it
on this query, which is usually the finding worth acting on.
Source code in src/ranklens/core/result.py
297 298 299 300 301 302 303 304 305 306 307 308 309 310 | |
WeightDiagnostics
dataclass
¶
How the weights 1/p of the rewarded documents of a log are distributed.
ess = (Σw)² / Σw²; ess_share = ess / n_weights — near 1 when the weights
are alike, near 0 when a few dominate. top1_mass is the share of the total
weight held by the largest 1% of weights. weights are the weights themselves,
one per rewarded document, for plotting their distribution.
Source code in src/ranklens/core/result.py
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | |
RankedList
dataclass
¶
Ranking for one query: docs[position] is shown at 0-based position.
Source code in src/ranklens/core/types.py
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | |
top
¶
top(k: int) -> tuple[DocId, ...]
First k documents (fewer if the list is shorter).
Source code in src/ranklens/core/types.py
53 54 55 56 57 | |