Source code for lossmodels.empirical.distribution

import numpy as np
from ..utils.random import RNGLike, resolve_rng

from ..frequency.base import FrequencyModel
from ..severity.base import SeverityModel


[docs] class EmpiricalSeverity(SeverityModel): """ Empirical severity model based on observed loss data. Parameters ---------- data : array-like Observed severity values. Must be nonempty and nonnegative. """ def __init__(self, data): data = np.asarray(data, dtype=float) if data.size == 0: raise ValueError("data must not be empty.") if np.any(data < 0): raise ValueError("severity data must be nonnegative.") self.data = data
[docs] def sample(self, size: int = 1, rng: RNGLike = None) -> np.ndarray: """ Generate bootstrap samples from the empirical severity distribution. """ if size <= 0: raise ValueError("size must be positive.") return resolve_rng(rng).choice(self.data, size=size, replace=True)
[docs] def mean(self) -> float: return float(np.mean(self.data))
[docs] def variance(self) -> float: return float(np.var(self.data, ddof=0))
[docs] def pdf(self, x: float) -> float: """ Empirical severity is discrete, so this returns the empirical point mass at x. For continuous-looking data, this will often be 0 except at exact observed values. """ if x < 0: return 0.0 return float(np.mean(self.data == x))
def cdf(self, x: float) -> float: if x < 0: return 0.0 return float(np.mean(self.data <= x))
[docs] def quantile(self, p): """Empirical quantile: the true inverse CDF ``inf{x : F(x) >= p}``. Returns an observed data point (``np.quantile`` with ``method="inverted_cdf"``), consistent with this class's own ``cdf`` and with the ecosystem VaR convention in ``lossmodels.aggregate.risk_measures``, ``risksim``, and ``extremeloss``. """ q = np.quantile(self.data, p, method="inverted_cdf") return float(q) if np.ndim(p) == 0 else np.asarray(q, dtype=float)
[docs] def excess_loss(self, d: float) -> float: """ E[(X - d)+] computed empirically. """ if d < 0: raise ValueError("d must be nonnegative.") return float(np.mean(np.maximum(self.data - d, 0.0)))
[docs] def limited_expected_value(self, d: float) -> float: """ E[min(X, d)] computed empirically. """ if d < 0: raise ValueError("d must be nonnegative.") return float(np.mean(np.minimum(self.data, d)))
def __repr__(self) -> str: return f"EmpiricalSeverity(n={len(self.data)})"
[docs] class EmpiricalFrequency(FrequencyModel): """ Empirical frequency model based on observed claim count data. Parameters ---------- data : array-like Observed claim counts. Must be nonempty, nonnegative, and integer-valued. """ def __init__(self, data): data = np.asarray(data) if data.size == 0: raise ValueError("data must not be empty.") if np.any(data < 0): raise ValueError("frequency data must be nonnegative.") if not np.all(np.equal(data, np.floor(data))): raise ValueError("frequency data must be integer-valued.") self.data = data.astype(int)
[docs] def sample(self, size: int = 1, rng: RNGLike = None) -> np.ndarray: """ Generate bootstrap samples from the empirical frequency distribution. """ if size <= 0: raise ValueError("size must be positive.") return resolve_rng(rng).choice(self.data, size=size, replace=True)
[docs] def mean(self) -> float: return float(np.mean(self.data))
[docs] def variance(self) -> float: return float(np.var(self.data, ddof=0))
def pmf(self, k: int) -> float: if k < 0: return 0.0 return float(np.mean(self.data == k)) def cdf(self, k: int) -> float: if k < 0: return 0.0 return float(np.mean(self.data <= k)) def __repr__(self) -> str: return f"EmpiricalFrequency(n={len(self.data)})"