Skip to main content

Unified model governance for UK insurance pricing: SS1/23-aligned validation and model risk management

Project description

insurance-governance

PyPI Python Tests License Open In Colab

💬 Questions or feedback? Start a Discussion. Found it useful? A ⭐ helps others find it.

Unified model governance for UK insurance pricing teams. Combines model validation and model risk management into one package, with tests and outputs structured to align with the principles of PRA SS1/23 (as adapted for insurance).

Merged from: insurance-validation (model validation reports) and insurance-mrm (model risk management).

Blog post: One Package, One Install: PRA SS1/23 Validation and MRM Governance Unified

The problem this solves: validation tests and MRM governance packs were built separately and had separate installs, separate version pinning, and separate import paths. Pricing teams either installed both and managed the coupling themselves, or skipped one. This package resolves that by providing a single install.

Regulatory note: PRA SS1/23 is a supervisory statement directed at banks and building societies, not insurers. Insurance model risk management is governed directly by PS12/22, Solvency II internal model requirements, and EIOPA validation guidelines. In practice, many UK insurance MRM frameworks reference SS1/23 by analogy — it articulates sound MRM principles regardless of firm type — and the PRA has encouraged insurers to take note. This library uses SS1/23 as a reference framework in that spirit: the validation tests and governance structure reflect its principles, but you should map your own obligations to your actual regulatory basis (PS12/22 or equivalent).

Subpackages

insurance_governance.validation

Model validation report generator, aligned with the principles of PRA SS1/23 (as adapted for insurance). Runs statistical tests (Gini, PSI, discrimination checks, Hosmer-Lemeshow, lift charts) and produces self-contained HTML reports.

insurance_governance.mrm

Model risk management framework. ModelCard metadata container, RiskTierScorer (objective 0-100 composite score mapping to Tier 1/2/3), ModelInventory (JSON file registry), GovernanceReport (executive committee pack).

Install

uv add insurance-governance

Quick start

import numpy as np
from insurance_governance import (
    ModelValidationReport,
    ValidationModelCard,
    MRMModelCard,
    RiskTierScorer,
    ModelInventory,
    GovernanceReport,
)

# --- Synthetic model outputs (replace with your real model predictions) ---
rng = np.random.default_rng(42)
n_val = 5_000
y_val        = rng.poisson(0.08, n_val).astype(float)          # observed claim counts
y_pred_val   = np.clip(rng.normal(0.08, 0.02, n_val), 0.001, None)  # model predictions
exposure_val = rng.uniform(0.5, 1.0, n_val)                    # policy years (required for A/E)

# --- Run statistical validation ---
card = ValidationModelCard(
    name="Motor Frequency v3.2",
    version="3.2.0",
    purpose="Predict claim frequency for UK motor portfolio",
    methodology="CatBoost gradient boosting with Poisson objective",
    target="claim_count",
    features=["age", "vehicle_age", "area", "vehicle_group"],
    limitations=["No telematics data"],
    owner="Pricing Team",
)
report = ModelValidationReport(
    model_card=card,
    y_val=y_val,
    y_pred_val=y_pred_val,
    exposure_val=exposure_val,
)
report.generate("validation_report.html")

# --- MRM governance pack ---
mrm_card = MRMModelCard(
    model_id="motor-freq-v3",
    model_name="Motor TPPD Frequency",
    version="3.2.0",
    model_class="pricing",
    intended_use="Frequency pricing for private motor.",
)
scorer = RiskTierScorer()
tier = scorer.score(
    gwp_impacted=125_000_000,
    model_complexity="high",
    deployment_status="champion",
    regulatory_use=False,
    external_data=False,
    customer_facing=True,
)
GovernanceReport(card=mrm_card, tier=tier).save_html("mrm_pack.html")

Or import from subpackages directly:

from insurance_governance.validation import ModelValidationReport, ModelCard as ValidationModelCard
from insurance_governance.mrm import ModelCard as MRMModelCard, RiskTierScorer, ModelInventory, GovernanceReport

Note on ModelCard

Both subpackages define a ModelCard class, but they serve different purposes:

  • insurance_governance.validation.ModelCard (ValidationModelCard at top level) — Pydantic schema, anchors the statistical validation report, captures features, methodology, limitations.
  • insurance_governance.mrm.ModelCard (MRMModelCard at top level) — dataclass, anchors the MRM governance pack, captures assumptions, risk tier, Model Risk Committee metadata.

At the top level they are re-exported as ValidationModelCard and MRMModelCard to avoid ambiguity.

Capabilities Demo

Demonstrated on synthetic motor data: 50,000 UK motor policies, CatBoost Poisson frequency model, 60/20/20 temporal train/validation/test split. Full script: benchmarks/benchmark_insurance_governance.py.

  • Runs a full validation suite in a single ModelValidationReport call: Gini coefficient with bootstrap 95% CI, 10-band lift chart, A/E by predicted decile with Poisson CI, Hosmer-Lemeshow goodness-of-fit, PSI on score distribution (train vs validation), monitoring plan completeness check — all returning TestResult objects with a pass/fail flag and human-readable detail
  • Computes an overall RAG status (Green/Amber/Red) from the worst-severity failure across all tests
  • Produces a self-contained HTML validation report and JSON sidecar, print-to-PDF ready, in under one second
  • Scores model risk tier via RiskTierScorer: 6 dimensions (GWP, model complexity, deployment status, regulatory use, external data, customer-facing) mapped to a 0-100 composite with documented rules per point — no subjective judgement required at the MRC presentation
  • Registers models in ModelInventory (JSON file, check into git alongside your code); records validation run history linked by run_id; lists overdue reviews
  • Generates a GovernanceReport executive committee pack (HTML + JSON) covering model purpose, risk tier rationale, last validation RAG, assumptions register with risk ratings, outstanding issues, approval conditions, and next review date

When to use: You have 10+ production pricing models and want consistent, auditable validation and governance output rather than bespoke analyst notebooks that vary by model. The framework is structured around the principles of PRA SS1/23 — insurers should map those principles to their own regulatory basis (PS12/22, EIOPA guidelines). Particularly useful before a PRA supervisory visit.

When NOT to use: You need reserving or capital model governance — this package is scoped to pricing models. It also does not replace independent human review of validation results; it automates the tests, not the judgement.

Databricks Notebook

A ready-to-run Databricks notebook benchmarking this library against standard approaches is available in burning-cost-examples.

Performance

Benchmarked on Databricks (2026-03-16) using synthetic UK motor data: 20,000 training + 8,000 validation policies, three model scenarios — well-specified (Model A), miscalibrated (Model B, A/E=1.18 with age-band bias), and drifted (Model C, trained on a shifted population). The comparison is the library's automated 5-test suite against a manual 4-check checklist. See benchmarks/benchmark_insurance_governance.py for the full script.

Runtime. On an 8,000-row validation set:

Approach Time
Manual 4-check checklist 0.09s
Automated 5-test suite (Gini + bootstrap CI, A/E + Poisson CI, Hosmer-Lemeshow, lift chart, PSI) 1.17s

The automated suite is ~13× slower in wall clock time; that 1-second overhead is entirely the 500-resample bootstrap for the Gini confidence interval.

What the automated suite catches that the manual checklist misses.

The key test is Model B (miscalibrated). Both methods flag the A/E deviation. But only the automated suite runs Hosmer-Lemeshow, which detects the age-band-level miscalibration that averages out in the global A/E: HL p < 0.0001 (reject calibration by group). The manual checklist, which computes one aggregate A/E number, cannot surface this pattern without additional code.

For Model C (drifted population), PSI on the score distribution = 0.189 — below the 0.25 threshold, so the manual checklist passes on PSI. Only the automated suite catches the drift, because it attaches a Poisson confidence interval to the A/E ratio: the CI excludes 1.0, flagging genuine miscalibration that the manual aggregate A/E misses. PSI alone is not sufficient to detect this type of drift; the confidence-interval-based A/E test is what surfaces it.

Scenario Manual verdict Automated verdict Key diagnostic
Model A (well-specified) 4/4 pass 5/5 pass Gini CI, A/E CI both tight
Model B (miscalibrated) Flags A/E Flags A/E + HL HL p<0.0001 — age-band bias
Model C (drifted) Passes PSI Flags A/E CI PSI=0.189 (below 0.25 threshold — manual checklist passes); A/E CI excludes 1.0

The runtime difference does not matter in practice — governance validation runs once per model release, not in a hot loop. The return is consistent, audit-ready output for all three scenarios: every test produces a TestResult with passed, severity, and a detail string ready for a validation pack.

Related Libraries

Library Description
insurance-monitoring Model drift detection — ongoing monitoring evidence feeds into governance review cycles
insurance-fairness Proxy discrimination auditing — fairness audit outputs are a required input to the governance sign-off pack
insurance-deploy Champion/challenger deployment with ENBP audit logging — governance documents the model; deploy manages its lifecycle

Licence

MIT

Project details


Download files

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

Source Distribution

insurance_governance-0.1.4.tar.gz (126.7 kB view details)

Uploaded Source

Built Distribution

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

insurance_governance-0.1.4-py3-none-any.whl (70.9 kB view details)

Uploaded Python 3

File details

Details for the file insurance_governance-0.1.4.tar.gz.

File metadata

  • Download URL: insurance_governance-0.1.4.tar.gz
  • Upload date:
  • Size: 126.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.8 {"installer":{"name":"uv","version":"0.10.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for insurance_governance-0.1.4.tar.gz
Algorithm Hash digest
SHA256 29f49136b3369a024927c00f573513d3f9602e5b8f95896040323fe35753c3c8
MD5 d1e2903b1cce577622dfab09ffde20e4
BLAKE2b-256 c194db48084c23b7d06cb62a92bbf8ba8f64570df3bce396958645eebc98b2ef

See more details on using hashes here.

File details

Details for the file insurance_governance-0.1.4-py3-none-any.whl.

File metadata

  • Download URL: insurance_governance-0.1.4-py3-none-any.whl
  • Upload date:
  • Size: 70.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.8 {"installer":{"name":"uv","version":"0.10.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for insurance_governance-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 d05215b8507d8c68f907561fc617ddcb32530c6bbb12c67e7b4d5d5a38823169
MD5 d0c5ec0d96e79aaf3e13be1c26b18d4a
BLAKE2b-256 00f60813c18d75358e3878ccfd2a7fae3679ff2254c4bcf7d171f7f3303da98e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page