kernels.MackFit

A fitted distribution-free chain ladder on one cohort.

Usage

Source

kernels.MackFit(
    cum,
    obs_mask,
    latest_dev,
    f,
    sigma2,
    s,
    n_obs,
    n_pos,
    origin_periods,
    dev_grain_months,
    sigma_rule,
    units=None,
    loss_field=None
)

Arrays are 0-based on both axes: dev index j spans 0 .. n_d - 1 and the development step j -> j + 1 carries f[j], sigma2[j], s[j] (its volume denominator), n_obs[j] (the origins behind the FACTOR) and n_pos[j] (the origins behind the SIGMA), each of length n_d - 1. The last two differ only where a pair origin has a zero cumulative; see the module docstring.

cum keeps the observed triangle (NaN outside it); full is the same matrix with the lower triangle filled by the chain-ladder projection, so full[:, -1] is the ultimate and full[i, j] for j > latest_dev[i] is the C-hat_{i,j} that Mack’s and Merz-Wuthrich’s variance formulas both evaluate at.

Parameter Attributes

cum: np.ndarray
obs_mask: np.ndarray
latest_dev: np.ndarray
f: np.ndarray
sigma2: np.ndarray
s: np.ndarray
n_obs: np.ndarray
n_pos: np.ndarray
origin_periods: list[dt.date]
dev_grain_months: int
sigma_rule: str
units: str | None = None
loss_field: str | None = None

Attributes

Name Description
full (n_w, n_d) observed triangle completed by the chain-ladder projection.
latest (n_w,) each origin’s cumulative loss on the latest diagonal.
reserve (n_w,) IBNR = ultimate - latest. Zero for a fully developed origin.
ultimate (n_w,) projected ultimate = the completed triangle’s last column.

full

(n_w, n_d) observed triangle completed by the chain-ladder projection.

full: np.ndarray


latest

(n_w,) each origin’s cumulative loss on the latest diagonal.

latest: np.ndarray


reserve

(n_w,) IBNR = ultimate - latest. Zero for a fully developed origin.

reserve: np.ndarray


ultimate

(n_w,) projected ultimate = the completed triangle’s last column.

ultimate: np.ndarray

Methods

Name Description
from_arrow() Decode a fit written by to_arrow(), refusing any other kind -
msep_runoff() Mack’s conditional MSEP of the FULL run-off reserve.
require_positive_open_diagonals() Every OPEN origin’s latest-diagonal cell must be strictly positive.
summary() One row per origin: latest, ultimate, IBNR and the run-off standard
to_arrow() Arrow IPC bytes. Carries n_obs and n_pos separately, because

from_arrow()

Decode a fit written by to_arrow(), refusing any other kind -

Usage

Source

from_arrow(data)

including the MackFitPanel it may well have come out of.


msep_runoff()

Mack’s conditional MSEP of the FULL run-off reserve.

Usage

Source

msep_runoff()

Mack (1993) formula (3), per accident year i:

msep_i = C-hat_{i,J}^2 * sum_{j=k_i}^{J-1} (sigma_j^2 / f_j^2)
                         * (1 / C-hat_{i,j} + 1 / S_j)

where k_i = latest_dev[i] is the dev index of i’s diagonal cell and J = n_d - 1. The 1/C-hat term is process risk, the 1/S_j term estimation risk; both are returned separately because cl.MackChainladder exposes them separately and the tie-out checks each. For the aggregate, Mack’s second formula adds the estimation-risk covariance between accident years, which share the same estimated factors:

msep_total = sum_i msep_i
           + 2 * sum_{i<k} C-hat_{i,J} C-hat_{k,J}
                 * sum_{j=k_i}^{J-1} (sigma_j^2 / f_j^2) / S_j

(the inner sum runs over the OLDER year’s dev range, which is the intersection of the two ranges). Process risk carries no cross term: accident years are independent under Mack’s assumptions.

Returns msep / process / parameter per origin (variances, not standard errors) plus the scalars msep_total, process_total, parameter_total.


require_positive_open_diagonals()

Every OPEN origin’s latest-diagonal cell must be strictly positive.

Usage

Source

require_positive_open_diagonals()

The factor estimator cannot enforce this and never could. Its c0 cells are exactly the cells with an observed successor, and on a run-off staircase an open origin’s diagonal cell has none - so the diagonal is the one cell class no factor-side guard ever sees. Every variance formula downstream then divides by it: msep_runoff’s process term (ratio_j / C-hat_{i,j} starting at j = latest_dev[i]) and Merz-Wuthrich’s Phi_i = ratio_k / C_{i,k} + ....

numpy divides silently, so without this the failure is invisible: a zero diagonal returns NaN msep for that origin AND a NaN total, a negative one returns a finite NEGATIVE msep whose square root is then NaN, and simulate_ultimates returns an exactly degenerate zero column because var = sigma2 * state is non-positive and every draw comes back at its mean. Nothing raises; the numbers are just wrong.

Deliberately NOT called on the point path. The chain-ladder ultimate is a product of factors off that cell and needs no positivity at all, and the gallery’s skill benchmark (scripts/compare_gallery.py) wants the ultimate even for a cohort whose variance is undefined. fit_mack therefore still succeeds; only msep_runoff / simulate_ultimates / the CDR refuse.

A CLOSED origin (already at the last dev column) is exempt: it has no remaining step, so nothing divides by its diagonal.


summary()

One row per origin: latest, ultimate, IBNR and the run-off standard

Usage

Source

summary()

error, plus a total row. Mirrors cl.MackChainladder.summary_.


to_arrow()

Arrow IPC bytes. Carries n_obs and n_pos separately, because

Usage

Source

to_arrow(*, compression=None)

they are different counts and the positivity contract is the difference.