Skip to main content

probcal

PyPI Downloads DOI License: MIT Python

Probability calibration you can put in front of a validator: numpy-only methods, metrics, and diagnostics for binary classifiers — built for regulated PD models, fully general in practice.

What the wedge is, concretely:

  • Regulated-PD first. Logit-scale diagnostics that keep 1% readable, per-grade regulatory backtests (binomial, Jeffreys), and a central-tendency adjustment that ships as an auditable LogitOffset stage — never a silent refit.
  • Audit trail everywhere. Every method explains its own parameters (interpret()); every fitted object serializes to versioned JSON (never pickle) with provenance fingerprints; every refusal names the reason and the alternative — no silent clamps, no silent approximations.
  • Exact inverse maps. "PD ≤ 2%" translates to a raw-score threshold, scorecard point cut-offs, or a counterfactual target, exactly (interval_inverse / point_inverse / Chain) — the contract recourse engines like treecf build on.
  • Anytime-valid monitoring. probcal.monitor watches deployed calibration with e-processes: the alarm keeps its type-I guarantee at every look, and reports whether a re-offset is enough or a re-fit is due.
  • numpy-only core. import probcal pulls numpy and nothing else — enforced by a test. scikit-learn/optbinning/treecf adapters are opt-in extras.

Start here: the executed end-to-end notebook takes one rare-event portfolio from GBM baseline to reliability diagnosis, selection with CIs, per-grade backtests, offsetting, threshold translation, a counterfactual, monitoring, and JSON round-trips.

probcal covers the binary calibration literature (Platt, temperature, beta, isotonic, centered isotonic, histogram binning, scaling-binning, BBQ, ENIR, Venn–Abers, spline), an extensive metric catalog with bootstrap CIs, automatic method selection under nested validation, and prefit/cv data flows.

Status: released on PyPI, beta. The API is stable enough to build on; breaking changes bump the minor version until 1.0 (see API stability in the docs). Serialized artifacts have a stronger promise: every 0.x release reads schema 1, enforced by golden files in CI.

Installation

pip install probcal            # runtime: numpy only
pip install "probcal[viz]"     # + matplotlib for probcal.plots
pip install "probcal[sklearn]" # + scikit-learn for probcal.sklearn adapters

Development setup (tests, lint, type-check):

git clone https://github.com/wlazlod/probcal && cd probcal
uv sync --extra dev

Quickstart

from probcal import BetaCalibrator, make_pd_portfolio
from probcal.metrics import calibration_guardrails

port = make_pd_portfolio(n=8000, random_state=42)   # synthetic 3% PD portfolio

g_before = calibration_guardrails(port.y, port.scores)
print(f"before: slope={g_before.slope:.3f}  intercept={g_before.intercept:+.3f}  ok={g_before.all_ok}")

cal = BetaCalibrator().fit(port.scores, port.y)
p = cal.predict_proba(port.scores)

g_after = calibration_guardrails(port.y, p)
print(f"after:  slope={g_after.slope:.3f}  intercept={g_after.intercept:+.3f}  ok={g_after.all_ok}")
print()
print(cal.interpret())

Output:

before: slope=0.968  intercept=-0.765  ok=False
after:  slope=1.000  intercept=+0.000  ok=True

Interpretation[BetaCalibrator]
parameter  value
---------  --------
a          0.875054
b          1.58922
c          -1.15227
- a = 0.875: sensitivity near s -> 0; a < 1 raises the smallest probabilities (model was overconfident in the low tail), a > 1 deepens them
- b = 1.589: sensitivity near s -> 1; the mirrored reading for the high tail
- c = -1.152: base-rate shift of -1.152 log-odds, odds factor 0.316
- identity map corresponds to (a, b, c) = (1, 1, 0)
- a != b (gap -0.714): asymmetric tail distortion that no symmetric (Platt/temperature) map could express

Automatic selection, model wrapping, offsetting, and threshold translation:

from probcal import CalibratedModel, CalibratorSelector, PlattCalibrator

sel = CalibratorSelector().fit(s_cal, y_cal)             # nested CV, log-loss criterion
wrapped = CalibratedModel(model, PlattCalibrator(), flow="prefit").fit(X_cal, y_cal)
wrapped.offset_to(target_mean=0.031)                     # auditable central-tendency stage
lo_z, hi_z = wrapped.interval_inverse(0.0, 0.02, space="logit")   # "PD <= 2%" in raw margins

Why probcal

Capability probcal scikit-learn netcal probcal (R)² single-method packages¹
Calibration methods 11 2 many 5 binary³ 1 each
Runtime dependencies numpy scipy stack torch stack native R varies
Logit-scale diagnostics (low-PD readable) yes
First-class auditable offset (central tendency) yes
Automatic selection under nested validation yes
Venn–Abers intervals yes venn-abers
Metric catalog with selection-suitability guidance yes partial partial partial
Per-grade regulatory backtests (binomial, Jeffreys) yes
Kernel calibration error and test (SKCE, Widmann et al.) yes yes
Calibrated→raw threshold translation (interval_inverse) yes
SHAP additivity repair on the calibrated scale yes
Parameter interpretation (interpret()) on every method yes partial

¹ betacal, venn-abers, ml-insights. ² prdm0/probcal (P. R. Diniz Marinho), unaffiliated — see the FAQ. Verified against v0.2.0, 2026-08-08. ³ Platt, temperature, beta, isotonic, histogram binning; its multiclass methods (Dirichlet, vector scaling, one-vs-rest) are out of probcal's binary scope.

Serialization

Every fitted object round-trips through versioned, human-readable JSON — never pickle (auditable; loading executes no code):

cal.to_json("beta.json")
loaded = BetaCalibrator.from_json("beta.json")   # bit-identical predictions
cal.fingerprint()                                # sha-256 provenance id

Compatibility promise: every 0.x release reads schema 1, enforced by committed golden files in CI; schema bumps ship only with a converter. Details: the Serialization concepts chapter.

Calibrators at a glance

Method Class Scaling
Platt scaling PlattCalibrator O(n) per IRLS iteration
Temperature scaling TemperatureCalibrator O(n) per IRLS iteration
Beta calibration BetaCalibrator O(n) per IRLS iteration
Isotonic regression IsotonicCalibrator O(n log n) fit (sort + PAVA)
Centered isotonic (CIR) CenteredIsotonicCalibrator O(n log n) fit
Histogram binning HistogramBinningCalibrator O(n log n) fit
Scaling-binning ScalingBinningCalibrator O(n log n) fit
BBQ BBQCalibrator O(n log n) fit per candidate binning
ENIR ENIRCalibrator quadratic in unique scores; intended for m ≲ 50,000 (fit warns above)
Venn–Abers (IVAP) VennAbersCalibrator O(n log n) fit, O(log n) per prediction
Spline calibration SplineCalibrator O(n · k) per IRLS iteration (k knots)
Segmented calibration SegmentedCalibrator base cost, plus O(n) for the per-segment offsets

Performance note: the ICI family (ici/e50/e90/emax) shares one LOESS fit anchored to grid_size=512 quantile points instead of refitting at every observation — the same device R's stats::lowess uses via its delta parameter (fit at spaced points, interpolate the rest) — and smooth_ece pre-aggregates its residual measure onto bins=8192 cells before the bandwidth bisection — for every n as of this release (0.1.3 ran the exact path for n ≤ 8192: ~1s at n=4000 on this host; now 1–6ms for all n up to 10⁵ and ~43ms at n=10⁶, where the O(n) pre-binning dominates). Measured on this host: ici at n=50,000 dropped from 192.2s (v0.1.2) to 1.2s, and loess(grid_size=512) now fits n=1,000,000 points in under 30s. grid_size=None and bins=None recover the exact pre-0.1.3 values and cost, so nothing is lost for portfolios small enough to afford it. Still numpy-only; Rust acceleration remains out of scope unless a future workload demands it.

Documentation

Built with mkdocs-material; run locally with uv run mkdocs serve. Start with Getting started, then the Concepts chapters — the package's theoretical foundation — and the executed PD calibration walkthrough notebook. The Visualization chapter is a gallery of every plot, regenerated deterministically by docs/scripts/generate_figures.py; the CORP reliability diagram, MCB-DSC plane, and score decomposition have their own CORP and score decomposition chapter.

License

MIT. See LICENSE. GPL-licensed R packages are used as conceptual references only; no GPL code is included.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

probcal-0.3.0.tar.gz (1.9 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

probcal-0.3.0-py3-none-any.whl (199.3 kB view details)

Uploaded Python 3

File details

Details for the file probcal-0.3.0.tar.gz.

File metadata

  • Download URL: probcal-0.3.0.tar.gz
  • Upload date:
  • Size: 1.9 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for probcal-0.3.0.tar.gz
Algorithm Hash digest
SHA256 2745331819411c7ca5d320f35103e2e1fbe0a4d650010bdcc1cf655e574318c7
MD5 4d901248cd3b9e6b6db0871b2a309dcf
BLAKE2b-256 8f7a96b7eaea9f18aa11ce9ecf159285bddbe9e993a3b067a09b979a608d5864

See more details on using hashes here.

Provenance

The following attestation bundles were made for probcal-0.3.0.tar.gz:

Publisher: publish.yml on wlazlod/probcal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file probcal-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: probcal-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 199.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for probcal-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 54f0cfd73c0c84b6da7f0b8296311d0c4b30fe4791aad8d0974938119cc7ad4f
MD5 6013d75322e37549da4e25d736f41430
BLAKE2b-256 e8fdaaa37debca7a5fbf3ee418a2fe9e7c819a2d41d95e63e521f86ef75f6a8e

See more details on using hashes here.

Provenance

The following attestation bundles were made for probcal-0.3.0-py3-none-any.whl:

Publisher: publish.yml on wlazlod/probcal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 files

0.2.0

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page