API: tools¶
offset
¶
Logit-offset (central tendency) adjustment with audit trail.
Theory — including the King–Zeng / Elkan / Tasche equivalences and the
uniqueness of the mode-B root: docs/concepts/offset.md.
References
King & Zeng (2001); Elkan (2001); Tasche (2013) — full records in the documentation.
AuditReport
dataclass
¶
AuditReport(delta: float, pre_mean: float, post_mean: float, timestamp: str, guardrails_before: GuardrailReport, guardrails_after: GuardrailReport)
Pre/post record of a logit-offset application, for validators.
| ATTRIBUTE | DESCRIPTION |
|---|---|
delta |
Applied log-odds shift.
TYPE:
|
pre_mean, post_mean |
Portfolio mean probability before and after the shift.
TYPE:
|
timestamp |
ISO-8601 UTC time at which the offset was fitted.
TYPE:
|
guardrails_before, guardrails_after |
The three-flag calibration health summary on the input and output probabilities.
TYPE:
|
LogitOffset
¶
LogitOffset(delta: float | None = None, target_mean: float | None = None)
Uniform log-odds shift: p' = sigma(logit(p) + delta).
Mode A takes delta explicitly; mode B takes target_mean and
solves mean(p') = target_mean for delta by bisection — the
portfolio mean is strictly increasing in delta, so the root is
unique (stated in the offset chapter and unit-tested). Exactly one of
the two arguments must be given.
The offset is deliberately not folded into any calibrator's
parameters: CalibratedModel.offset_to appends it as a separate,
inspectable pipeline stage.
| ATTRIBUTE | DESCRIPTION |
|---|---|
delta_ |
Fitted (or given) shift in log-odds.
TYPE:
|
pre_mean_, post_mean_ |
Portfolio mean before and after, recorded at fit time.
TYPE:
|
timestamp_ |
ISO-8601 UTC fit time — part of the audit trail.
TYPE:
|
Source code in src/probcal/offset.py
90 91 92 | |
affine_logit_coeffs_
property
¶
affine_logit_coeffs_: tuple[float, float]
(1, delta): the offset is affine on the logit scale.
fit
¶
fit(p: object, sample_weight: object = None) -> Self
Fix delta (mode A) or solve it against the target mean (mode B).
| PARAMETER | DESCRIPTION |
|---|---|
p
|
Current calibrated probabilities of the portfolio.
TYPE:
|
sample_weight
|
Weights for the portfolio mean.
TYPE:
|
Source code in src/probcal/offset.py
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | |
transform
¶
transform(p: object) -> ndarray
Apply the fitted shift to probabilities.
Source code in src/probcal/offset.py
126 127 128 129 130 | |
interpret
¶
interpret() -> Interpretation
Read delta in log-odds, odds-factor, and central-tendency terms.
Source code in src/probcal/offset.py
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | |
interval_inverse
¶
interval_inverse(lo: float, hi: float, *, space: str = 'probability', buffer_logit: float = 0.0) -> tuple[float, float]
Closed-form preimage: subtract delta on the logit scale.
Same protocol as BaseCalibrator.interval_inverse; the offset's
output range is the full unit interval, so only a crossed buffer can
make a target unattainable.
Source code in src/probcal/offset.py
160 161 162 163 164 165 166 167 168 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 194 195 196 | |
audit_report
¶
audit_report(y: object, p: object, *, sample_weight: object = None) -> AuditReport
Pre/post guardrail comparison for the validator's one-table view.
Source code in src/probcal/offset.py
198 199 200 201 202 203 204 205 206 207 208 209 210 211 | |
wrapper
¶
CalibratedModel: model-level wrapper with prefit and cross-validation flows.
Theory of the flows (why prefit is the credit-risk canon, why the pooled cv
variant is the recommended default): docs/concepts/data-splitting.md.
CalibratedModel
¶
CalibratedModel(model: Any, calibrator: BaseCalibrator, flow: str = 'prefit', cv: int = 5, ensemble: bool = False, random_state: int = 42)
Wrap any scoring model with a probcal calibrator (and optional offsets).
| PARAMETER | DESCRIPTION |
|---|---|
model
|
Duck-typed model with
TYPE:
|
calibrator
|
Unfitted calibrator instance (its parameters are cloned per fold in
the cv flow via
TYPE:
|
flow
|
TYPE:
|
cv
|
Fold count for the cv flow (stratified, seeded).
TYPE:
|
ensemble
|
TYPE:
|
random_state
|
Seed for the fold assignment.
TYPE:
|
| ATTRIBUTE | DESCRIPTION |
|---|---|
model_ |
The deployed model (the input model for prefit; the full-data refit for pooled cv).
TYPE:
|
calibrator_ |
The fitted calibrator (pooled/prefit flows).
TYPE:
|
ensemble_ |
The fold pairs (ensemble flow only).
TYPE:
|
offsets_ |
Appended offset stages, each separately inspectable.
TYPE:
|
Source code in src/probcal/wrapper.py
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | |
is_monotone_
property
¶
is_monotone_: bool
Monotone iff the calibrator stage is (offsets always are).
affine_logit_coeffs_
property
¶
affine_logit_coeffs_: tuple[float, float] | None
Composed (a, b + sum(deltas)) when the calibrator stage is affine.
fit
¶
fit(X: object, y: object, sample_weight: object = None) -> Self
Fit the calibration stage per the configured flow.
Source code in src/probcal/wrapper.py
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | |
predict_proba
¶
predict_proba(X: object) -> ndarray
Calibrated (and offset) probabilities P(y=1) for new inputs.
Source code in src/probcal/wrapper.py
165 166 167 168 169 170 171 | |
predict_proba_2d
¶
predict_proba_2d(X: object) -> ndarray
Sklearn-style (n, 2) probability matrix.
Source code in src/probcal/wrapper.py
173 174 175 176 | |
offset_to
¶
offset_to(target_mean: float | None = None, delta: float | None = None, X: object = None) -> Self
Append an inspectable :class:LogitOffset stage.
Mode B (target_mean) anchors the portfolio mean of the current
pipeline output — computed on X when given, else on the stored
calibration scores (DECISIONS 48). The offset is never folded into
the calibrator's parameters.
Source code in src/probcal/wrapper.py
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 | |
interval_inverse
¶
interval_inverse(lo: float, hi: float, *, space: str = 'probability', buffer_logit: float = 0.0) -> tuple[float, float]
Preimage of a calibrated interval through the full pipeline.
Composes right-to-left: the buffer shrinks the final interval, each
offset subtracts its delta on the logit scale, and the calibrator's
own inverse finishes the job. Returns bounds on the model's
probability output (space="probability") or their logits.
Source code in src/probcal/wrapper.py
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 | |
interpret
¶
interpret() -> Interpretation
Concatenated interpretation of the calibrator and every offset stage.
Source code in src/probcal/wrapper.py
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 | |
selection
¶
CalibratorSelector: automatic method selection under nested validation.
The selector's scoring path only ever receives out-of-fold predictions —
selection on fitting data is an unrepresentable state, not a documented
misuse. Protocol, criteria, and report reading:
docs/concepts/auto-selection.md.
CalibratorSelector
¶
CalibratorSelector(candidates: dict[str, BaseCalibrator] | None = None, scoring: str = 'log_loss', cv: int = 5, random_state: int = 42)
Choose a calibrator by inner cross-validation on the calibration data.
| PARAMETER | DESCRIPTION |
|---|---|
candidates
|
Candidate instances (cloned per fold via
TYPE:
|
scoring
|
Out-of-fold selection criterion, lower is better. Plain ECE and Hosmer–Lemeshow are refused — see the metrics chapter's table.
TYPE:
|
cv
|
Inner stratified fold count.
TYPE:
|
random_state
|
Seed for the fold assignment.
TYPE:
|
| ATTRIBUTE | DESCRIPTION |
|---|---|
best_name_ |
Winning candidate's name.
TYPE:
|
best_calibrator_ |
The winner refitted on the full calibration set.
TYPE:
|
report_ |
Ranked table: mean ± sd of the criterion, guardrail flags, chosen marker.
TYPE:
|
Source code in src/probcal/selection.py
93 94 95 96 97 98 99 100 101 102 103 | |
fit
¶
fit(s: object, y: object, sample_weight: object = None) -> CalibratorSelector
Run the nested selection and refit the winner on all data.
Source code in src/probcal/selection.py
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 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 | |
predict_proba
¶
predict_proba(s: object) -> ndarray
Delegate to the refitted winner.
Source code in src/probcal/selection.py
168 169 170 | |
interpret
¶
interpret() -> Interpretation
Delegate to the refitted winner.
Source code in src/probcal/selection.py
172 173 174 | |
curves
¶
Reliability-curve builders and the GiViTI-style calibration belt.
Numpy-only; every result is a frozen dataclass carrying both probability- and
logit-scale coordinates, plotting-backend-agnostic (rendering lives in
probcal.plots). Theory: docs/concepts/visualization.md.
References
Austin & Steyerberg (2014); Nattino, Finazzi & Bertolini (2014); Nattino, Lemeshow, Phillips, Finazzi & Bertolini (2017) — full records in the documentation. The belt is reimplemented from the papers; no GPL code is used.
EcceCurve
dataclass
¶
EcceCurve(frac: ndarray, cumdev: ndarray, sd_null: ndarray, stat_max: float, argmax_frac: float)
Cumulative-deviation walk over predictions sorted ascending (ECCE).
reliability_binned
¶
reliability_binned(y: object, p: object, *, n_bins: int = 10, strategy: str = 'mass', sample_weight: object = None) -> ReliabilityCurve
Binned reliability curve with Wilson confidence intervals.
| PARAMETER | DESCRIPTION |
|---|---|
y
|
Outcomes and predicted probabilities.
TYPE:
|
p
|
Outcomes and predicted probabilities.
TYPE:
|
n_bins
|
Requested bin count.
TYPE:
|
strategy
|
Equal-count (default) or equal-width bins.
TYPE:
|
sample_weight
|
Weights for the bin means; Wilson CIs use raw counts.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
ReliabilityCurve
|
Per-bin mean prediction, event rate, count, Wilson CI, and the logit-scale coordinates. |
Source code in src/probcal/curves.py
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 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | |
reliability_loess
¶
reliability_loess(y: object, p: object, *, frac: float = 0.75, grid_size: int = 100, sample_weight: object = None) -> SmoothReliabilityCurve
LOESS-smoothed reliability curve on a grid (Austin & Steyerberg, 2014).
Source code in src/probcal/curves.py
89 90 91 92 93 94 95 96 97 98 99 100 101 | |
reliability_spline
¶
reliability_spline(y: object, p: object, *, grid_size: int = 100, sample_weight: object = None) -> SmoothReliabilityCurve
Spline-smoothed reliability curve on a grid (penalized natural cubic spline of the outcome on the logit prediction).
Source code in src/probcal/curves.py
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | |
ecce_curve
¶
ecce_curve(y: object, p: object, *, sample_weight: object = None) -> EcceCurve
Cumulative-deviation walk for the ECCE plot (Arrieta-Ibarra et al., 2022).
Sorts by prediction and accumulates weighted residuals, mirroring
metrics.ecce exactly so stat_max agrees with the metric.
sd_null is the pointwise standard deviation of the walk under
calibration — an envelope for reading, not a simultaneous band.
Source code in src/probcal/curves.py
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | |
calibration_belt
¶
calibration_belt(y: object, p: object, *, confidence: tuple[float, float] = (0.8, 0.95), grid_size: int = 100, sample_weight: object = None) -> BeltResult
GiViTI-style calibration belt (Nattino et al., 2014, 2017).
Fits a polynomial logistic recalibration of the outcome on
logit(p), selecting the degree by forward likelihood-ratio testing
(p < 0.05 to add a term, capped at degree 4), then draws pointwise
confidence bands from the information-matrix ellipsoid — a Wald
approximation of the LR-region inversion (DECISIONS entry). The
associated p-value tests the fitted polynomial against the identity.
Where the band excludes the diagonal, the data reject calibration in
that region.
Source code in src/probcal/curves.py
161 162 163 164 165 166 167 168 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 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 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 | |
plots
¶
Matplotlib plotting helpers (requires the [viz] extra; import-guarded).
All computation lives in probcal.curves and probcal.metrics; this
module only renders. The logit-scale views are the flagship for low-PD
portfolios: axis ticks sit at logit positions but are labeled in
probabilities, so the low-probability region stays readable. Styling is
applied per call via rc_context — global rcParams are never touched.
Theory: docs/concepts/visualization.md.
plot_reliability
¶
plot_reliability(curve: ReliabilityCurve, *, smooth: SmoothReliabilityCurve | None = None, scale: str = 'probability', y: object = None, p: object = None, annotate: bool = True, rug: bool = True, counts: bool = False, ax: Any = None) -> Any
Annotated reliability diagram: binned points with Wilson CIs, optional smooth overlay, stats box, and event/non-event rug.
scale="logit" stretches the low-probability region — the recommended
view for PD portfolios. Bins whose event rate is exactly 0 or 1 have no
finite logit and are omitted from the logit-scale point layer; they remain
visible in the rug (or the counts=True margin).
Passing the raw y/p enables the stats box (annotate=True,
computed by :func:probcal.metrics.reliability_summary) and the rug
(rug=True, events along the top edge, non-events along the bottom,
deterministically thinned to at most 1000 marks per class). Both are
silently skipped when y/p are absent. counts=True restores the
twin-axis count-bar margin.
Source code in src/probcal/plots.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 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 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 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | |
plot_belt
¶
plot_belt(belt: BeltResult, *, scale: str = 'probability', ax: Any = None) -> Any
GiViTI-style calibration belt with 80/95% bands and the test p-value.
Source code in src/probcal/plots.py
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | |
plot_comparison
¶
plot_comparison(before: ReliabilityCurve, after: ReliabilityCurve, *, scale: str = 'probability', labels: tuple[str, str] = ('before', 'after')) -> Any
Side-by-side reliability diagrams (pre/post calibration or offset).
Source code in src/probcal/plots.py
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 | |
plot_interval
¶
plot_interval(intervals: ndarray, s: ndarray, *, ax: Any = None) -> Any
Venn–Abers interval widths against the score: where is calibration uncertain?
Source code in src/probcal/plots.py
246 247 248 249 250 251 252 253 254 255 256 257 258 | |
plot_selection
¶
plot_selection(report: SelectionReport, *, ax: Any = None) -> Any
SelectionReport as a ranked dot plot with fold-spread whiskers.
Source code in src/probcal/plots.py
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 | |
plot_ecce
¶
plot_ecce(curves: Any, *, labels: Any = None, show_band: bool = True, ax: Any = None) -> Any
ECCE cumulative-drift walk(s) from :func:probcal.curves.ecce_curve.
Accepts a single EcceCurve or a sequence (e.g. raw vs calibrated).
The grey envelope (show_band=True, from the first curve) is ±2
pointwise standard deviations under calibration — an aid for reading
the walk, NOT a simultaneous confidence band; the formal max-statistic
test of Arrieta-Ibarra et al. (2022) is out of scope for this release.
Source code in src/probcal/plots.py
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 | |
plot_grade_backtest
¶
plot_grade_backtest(result: Any, *, log_scale: bool = True, ax: Any = None) -> Any
Per-grade traffic-light backtest chart (Jeffreys or exact binomial).
Observed default rates as circles colored by the grade's traffic light,
grey 90% display intervals (ci_low/ci_high), and the assigned PDs
as wide blue dashes. The intervals are display companions only — the
verdict is carried by the lights from the unchanged one-sided tests, so
no p-values are printed on the canvas. log_scale=True is the right
default for PD grades spanning orders of magnitude.
Source code in src/probcal/plots.py
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 | |
plot_offset_audit
¶
plot_offset_audit(offset: Any, *, ax: Any = None) -> Any
Audit chart for a fitted :class:probcal.offset.LogitOffset stage.
Draws the offset map t -> t + delta on the logit scale against the
identity, marks the pre- and post-adjustment central tendencies, and
prints the audit numbers read directly from the fitted attributes. This
chart audits the stage, not the outcomes — for the before/after
guardrail comparison use LogitOffset.audit_report(y, p).
Source code in src/probcal/plots.py
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 | |
attribution
¶
SHAP / additive-attribution adjustment to calibrated outputs.
Post-hoc calibration breaks SHAP local accuracy: base + sum(phi)
reconstructs the raw score, not the calibrated probability. This module
restores additivity on the calibrated scale — exactly for calibrators affine
on the logit scale, and by the Aumann–Shapley secant rescaling in general.
Theory, identifiability limits, and invariance properties:
docs/concepts/shap-calibration.md.
No shap import: plain arrays are accepted, and shap.Explanation objects
are duck-typed via their .values / .base_values attributes.
References
Lundberg & Lee (2017); Lundberg et al. (2020); Sundararajan, Taly & Yan (2017); Aumann & Shapley (1974) — full records in the documentation.
AdjustedAttribution
dataclass
¶
AdjustedAttribution(phi_adj: ndarray, base_adj: ndarray, target: ndarray, method_used: str, max_reconstruction_error: float)
Attributions rescaled to the calibrated output scale.
| ATTRIBUTE | DESCRIPTION |
|---|---|
phi_adj |
Adjusted per-feature attributions.
TYPE:
|
base_adj |
Adjusted base values.
TYPE:
|
target |
The calibrated output each row reconstructs
(
TYPE:
|
method_used |
TYPE:
|
max_reconstruction_error |
TYPE:
|
adjust_attributions
¶
adjust_attributions(phi: object, base_value: object, calibrator: Any, *, scale: str = 'logit', method: str = 'auto') -> AdjustedAttribution
Rescale additive attributions so they sum to the calibrated output.
| PARAMETER | DESCRIPTION |
|---|---|
phi
|
Raw attributions on the model's score scale (log-odds margins for
TYPE:
|
base_value
|
SHAP base value(s) on the same scale as
TYPE:
|
calibrator
|
Any object with
TYPE:
|
scale
|
Working scale of the attributions. Affine-exactness exists only on the logit scale.
TYPE:
|
method
|
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
AdjustedAttribution
|
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If |
Source code in src/probcal/attribution.py
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 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 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 167 168 169 170 171 | |
thresholds
¶
Calibrated-to-raw interval and masterscale-band mapping.
Thin functional wrappers over the calibrators' interval_inverse protocol
(spec §10): numpy-only, arrays and floats, no knowledge of any consumer. The
canonical rating-grade workflow — masterscale bands defined on calibrated PD,
translated once per recalibration into raw-score intervals — is
calibrated_bands_to_raw; its output plugs directly into band-style raw
targets of a counterfactual engine.
calibrated_interval_to_raw
¶
calibrated_interval_to_raw(calibrator: object, lo: float, hi: float, *, space: str = 'probability', buffer_logit: float = 0.0) -> tuple[float, float]
Translate one calibrated-probability interval into raw-score bounds.
| PARAMETER | DESCRIPTION |
|---|---|
calibrator
|
Any object implementing the duck-typed protocol
TYPE:
|
lo
|
Calibrated bounds;
TYPE:
|
hi
|
Calibrated bounds;
TYPE:
|
space
|
Scale of the returned bounds.
TYPE:
|
buffer_logit
|
Robustness margin applied in logit space before inversion.
TYPE:
|
Source code in src/probcal/thresholds.py
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | |
calibrated_bands_to_raw
¶
calibrated_bands_to_raw(calibrator: object, bands: dict, *, space: str = 'probability', buffer_logit: float = 0.0) -> dict
Translate a masterscale {grade: (lo, hi)} on calibrated PD to raw intervals.
Grade edges are policy artifacts that outlive model versions; this translation is what changes when the calibrator is refitted.
Source code in src/probcal/thresholds.py
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | |
datasets
¶
Synthetic dataset generators (make_pd_portfolio).
PdPortfolio
dataclass
¶
PdPortfolio(scores: ndarray, y: ndarray, p_true: ndarray)
Synthetic PD portfolio: model scores, outcomes, and the true probabilities.
| ATTRIBUTE | DESCRIPTION |
|---|---|
scores |
The model's reported PDs — miscalibrated unless generated with
TYPE:
|
y |
Bernoulli outcomes drawn from
TYPE:
|
p_true |
True conditional probabilities (mean anchored at
TYPE:
|
make_pd_portfolio
¶
make_pd_portfolio(n: int = 5000, *, event_rate: float = 0.03, slope: float = 0.7, intercept: float = 0.0, asymmetry: float = 0.4, score_location: float = -3.2, score_scale: float = 1.1, random_state: int = 42) -> PdPortfolio
Generate a synthetic, controllably miscalibrated PD portfolio.
The model's scores are drawn as s = sigma(N(score_location,
score_scale)); the true probability follows the beta-calibration family
logit p_true = a_lo * ln(s) - a_hi * ln(1 - s) + c
with a_lo = slope * (1 + asymmetry) (low-PD tail) and a_hi = slope
(high tail), so asymmetry != 0 produces exactly the one-sided tail
distortion low-event-rate portfolios exhibit, and BetaCalibrator can
recover the generative exponents. c absorbs intercept plus a
portfolio-level anchor solved so that mean(p_true) == event_rate
(unique by monotonicity, via bisection). With slope=1, asymmetry=0,
intercept=0 the scores are exactly calibrated.
| PARAMETER | DESCRIPTION |
|---|---|
n
|
Portfolio size.
TYPE:
|
event_rate
|
Target mean of
TYPE:
|
slope
|
Base exponent of the distortion;
TYPE:
|
intercept
|
Additional log-odds shift applied before the mean anchor is solved.
TYPE:
|
asymmetry
|
Relative extra distortion of the low-PD tail (
TYPE:
|
score_location
|
Parameters of the normal generating the score logits.
TYPE:
|
score_scale
|
Parameters of the normal generating the score logits.
TYPE:
|
random_state
|
Seed.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
PdPortfolio
|
|
Source code in src/probcal/datasets.py
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 68 69 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 | |