Skip to main content

tests PyPI Python 3.10+ License: MIT Status: Alpha

whsmooth

Whittaker-Henderson smoothing for P&C ratemaking and actuarial graduation --- 1D, 2D, automatic lambda selection.


What is whsmooth?

Whittaker-Henderson smoothing is a workhorse technique across actuarial practice: smoothing claim severity by exposure cell, graduating loss development factors, stabilizing rate relativities, and graduating mortality tables. The method has been used since the 1920s; it minimizes a weighted sum of fidelity to the data and roughness of the smoothed curve, controlled by a single parameter lambda.

Despite its centrality, no dedicated Python implementation exists. R has MortalitySmooth and ungroup, both life-actuarial. Python practitioners --- especially in P&C --- are left writing ad-hoc scripts.

whsmooth fills this gap with:

  • P&C-first design --- built for severity, frequency, LDF, and rate relativity smoothing, with mortality graduation as a natural special case.
  • Sparse-matrix solver --- banded penalty system solved with scipy.sparse for O(n) performance.
  • Principled lambda selection --- REML, GCV, and AIC, so you stop guessing your smoothing parameter.
  • 1D and 2D --- smooth a vector by vehicle age, or an entire age × territory grid in one call.
  • Sklearn-style API --- fit(y).fitted_, no surprises.

Installation

pip install whsmooth

# With plotting helpers
pip install "whsmooth[plot]"

# With pandas integration
pip install "whsmooth[pandas]"

Quickstart --- Smoothing claim severity by vehicle age

import numpy as np
from whsmooth import WH1D

# Observed mean severity by vehicle age (0-25), with claim counts as weights
ages = np.arange(0, 26)
severity_obs = np.array([
    8050, 8120, 8210, 8290, 8390, 8520, 8680, 8850, 9050, 9270,
    9510, 9770, 10050, 10350, 10670, 11010, 11380, 11760, 12300, 12800,
    13100, 14200, 13400, 15100, 14000, 16500,
])
counts = np.array([
    5200, 4500, 3900, 3400, 2950, 2550, 2200, 1900, 1640, 1420,
    1230, 1060, 920, 790, 685, 590, 510, 440, 380, 330,
    285, 245, 210, 180, 155, 135,
])

# Fit with GCV-selected lambda; weights = exposure
wh = WH1D(lam='gcv', order=2).fit(severity_obs, weights=counts)

print(f"Selected lambda: {wh.lambda_:.2f}")
print(f"Effective degrees of freedom: {wh.edf_:.2f}")
smoothed = wh.fitted_

The high-credibility cells (low ages, large counts) are tracked closely; the sparse tail (older vehicles) is stabilized toward the underlying trend instead of chasing noise.

Quickstart --- 2D smoothing on age × territory

from whsmooth import WH2D

# Pure premium grid: 10 age bands × 8 territories
pure_premium = ...  # shape (10, 8)
exposure = ...      # shape (10, 8)

wh2 = WH2D(lam=('gcv', 'gcv'), order=(2, 2)).fit(pure_premium, weights=exposure)
pp_smooth = wh2.fitted_

Other use cases

  • LDF smoothing: stabilize loss development factors before extrapolation.
  • Frequency relativities: smooth claim frequency by exposure class.
  • Mortality graduation (life): graduate qx by age --- same algorithm, drop in your qx_crude and exposure.
# Mortality graduation example
wh = WH1D(lam='reml', order=2).fit(qx_crude, weights=exposure)
qx_grad = wh.fitted_

Features

Module Description
WhittakerHenderson1D / WH1D 1D smoothing, any difference order, weighted
WhittakerHenderson2D / WH2D 2D smoothing on grids (Kronecker penalties)
lam='gcv' / 'reml' / 'aic' Automatic lambda selection
whsmooth.diagnostics gcv_score, reml_score, aic_score, edf
whsmooth._penalties Difference penalty matrices, composite penalties

How it works

The Whittaker-Henderson smoother solves:

min_a   sum_i w_i (y_i - a_i)^2  +  lambda * ||D_d a||^2

where D_d is the d-th order difference matrix and lambda controls the smoothness-fidelity tradeoff. The system has a banded coefficient matrix and is solved via sparse Cholesky factorization --- O(n) instead of O(n^3).

For 2D problems, the penalty extends to Kronecker products of row and column difference matrices, following Currie, Durban & Eilers (2004).

References

P&C / general

  • Werner, G. & Modlin, C. (2016). Basic Ratemaking (5th ed.). Casualty Actuarial Society.
  • Verrall, R. J. (1996). "Claims Reserving and Generalised Additive Models." Insurance: Mathematics and Economics, 19(1), 31-43.
  • Eilers, P. H. C. & Marx, B. D. (1996). "Flexible Smoothing with B-splines and Penalties." Statistical Science, 11(2), 89-121.

Original

  • Whittaker, E. T. (1922). "On a New Method of Graduation." Proc. Edinburgh Math. Soc., 41, 63-75.
  • Henderson, R. (1924). "A New Method of Graduation." Trans. Actuarial Society of America, 25, 29-40.

Life / mortality

  • Currie, I. D., Durban, M. & Eilers, P. H. C. (2004). "Smoothing and Forecasting Mortality Rates." Statistical Modelling, 4(4), 279-298.
  • Camarda, C. G. (2012). "MortalitySmooth: An R Package for Smoothing Poisson Counts with P-Splines." J. Statistical Software, 50(1), 1-24.

Part of the actuarial Python ecosystem

whsmooth is part of a 6-library P&C actuarial stack:

  • actudist --- severity & frequency distributions
  • burncost --- burning cost analysis
  • actuarcredibility --- credibility methods
  • whsmooth --- smoothing (this library)
  • pyratemaking --- rating tables (coming)
  • pyinsurancerating --- rating engine (coming)

Contributing

See CONTRIBUTING.md. PRs welcome --- open an issue first to discuss substantive changes.

Citation

If you use whsmooth in academic work, see CITATION.cff or:

López, I. (2026). whsmooth: Whittaker-Henderson smoothing for P&C ratemaking in Python (v0.1.0). https://github.com/CosmikArt/whsmooth

Author

Isaac López

License

MIT

Metadata

Release files for whsmooth 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for whsmooth 0.1.0
File Size Uploaded
whsmooth-0.1.0.tar.gz 15.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for whsmooth 0.1.0
File Interpreter ABI Platform
whsmooth-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 29.8 kB

Release files / whsmooth-0.1.0.tar.gz

Download URL whsmooth-0.1.0.tar.gz
Size 15.3 kB
Tags Source
SHA-256 checksum
How to use checksums
a6e68aa2a2d97213a88af1dcd07d4135d41bc61b115a3e5a7fbcd000581702d1
BLAKE2b-256 checksum
How to use checksums
9522868b2dce41b21b04462d748c075aca74dc53c216d54b3c0ece7bc7526c20
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.9

Release files / whsmooth-0.1.0-py3-none-any.whl

Download URL whsmooth-0.1.0-py3-none-any.whl
Size 14.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c027a8f5413dbac97680c2d895894aa88f0553bdea07992135d0d117066bb7fb
BLAKE2b-256 checksum
How to use checksums
59ece89f837d3e193bb04864164575cbff431a7e14ab9e9894e5f0ade4977c25
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.9

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release 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