GenPareto#
- class pymc_extras.distributions.GenPareto(name: str, *args, rng=None, dims: str | Sequence[str | None] | None = None, initval=None, observed=None, total_size=None, transform=UNSET, default_transform=UNSET, **kwargs)[source]#
Generalized Pareto distribution.
The Generalized Pareto distribution (GPD) is the canonical model for exceedances over a threshold (peaks-over-threshold), the counterpart of the GEV used for block maxima. Its CDF is
\[\begin{split}G(x \mid \mu, \sigma, \xi) = \begin{cases} 1 - \left(1 + \xi\,\frac{x - \mu}{\sigma}\right)^{-1/\xi}, & \xi \neq 0, \\[6pt] 1 - \exp\!\left(-\dfrac{x - \mu}{\sigma}\right), & \xi = 0. \end{cases}\end{split}\]The shape \(\xi\) is parametrized as in Scarrott and MacDonald (2012) [1], matching SciPy’s
genparetocparameter.(
Source code,png,hires.png,pdf)
Support
\(\begin{cases} x \geq \mu, & \xi \geq 0 \\ \mu \leq x < \mu - \sigma/\xi, & \xi < 0 \end{cases}\)
Mean
\(\begin{cases} \mu + \dfrac{\sigma}{1 - \xi}, & \xi < 1 \\ \infty, & \xi \geq 1 \end{cases}\)
Variance
\(\begin{cases} \dfrac{\sigma^2}{(1 - \xi)^2 (1 - 2\xi)}, & \xi < 1/2 \\ \infty, & \xi \geq 1/2 \end{cases}\)
Median
\(\begin{cases} \mu + \dfrac{\sigma (2^{\xi} - 1)}{\xi}, & \xi \neq 0 \\ \mu + \sigma \ln 2, & \xi = 0 \end{cases}\)
Mode
\(\begin{cases} \mu, & \xi \geq -1 \\ \mu - \sigma/\xi, & \xi \leq -1 \end{cases}\)
Entropy
\(\ln \sigma + \xi + 1\)
- Parameters:
mu (tensor_like of float) – Location parameter (the threshold).
sigma (tensor_like of float) – Scale parameter (sigma > 0).
xi (tensor_like of float) – Shape parameter. \(\xi > 0\) gives a heavy (Pareto) tail, \(\xi = 0\) an exponential tail, and \(\xi < 0\) a bounded upper tail.
References
Notes
The support is \([\mu, \infty)\) for \(\xi \geq 0\). For \(\xi < 0\), the support has a finite right endpoint \(x_F := \mu - \sigma/\xi\); values at or above \(x_F\) have density \(0\). Since \(x_F\) depends on \(\sigma\) and \(\xi\), a fit that leaves them free must keep every observation inside the support (see Modeling recommendations).
The \(r\)-th moment is finite iff \(\xi < 1/r\). Thus the mean is finite for \(\xi < 1\) and the variance for \(\xi < 1/2\). Every moment exists for \(\xi \leq 0\).
Examples
Fitting exceedances over a known threshold:
import pymc as pm from pymc_extras.distributions import GenPareto exceedances = data[data > threshold] xmax = exceedances.max() with pm.Model(): # sigma carries the data's units; use a wide log-scale prior when the # data scale is unknown. pareto_sigma = pm.LogNormal("pareto_sigma", mu=0.0, sigma=10.0) # xi lower bound: see Modeling recommendations. pareto_xi = pm.TruncatedNormal( "pareto_xi", mu=0.0, sigma=2.0, lower=pm.math.maximum(-1.0, -pareto_sigma / (xmax - threshold)), ) GenPareto("obs", mu=threshold, sigma=pareto_sigma, xi=pareto_xi, observed=exceedances) idata = pm.sample()
Modeling recommendations
Keep the data inside the support. If \(\xi\) is allowed to be negative, the support has a finite upper wall \(x = x_F\), where \(x_F := \mu - \sigma/\xi\), and the observations stay inside it only when \(\max(\text{data}) < x_F\), equivalently \(\xi > -\sigma/(\max(\text{data}) - \mu)\). Encoding this as the \(\xi\) prior’s lower bound keeps \(x_F\) above the data; without it the sampler can reach \((\sigma, \xi)\) for which \(x_F < \max(\text{data})\), putting an observation out of support and causing divergences. (\(\xi \geq 0\) has no upper wall and always contains the data.)
Floor \(\xi\) at \(-1\). If \(\xi\) is allowed below \(-1\), the density diverges at the wall \(x = x_F\): as \(x_F\) decreases toward \(\max(\text{data})\) the likelihood tends to \(+\infty\). Choose the \(\xi\) prior to enforce \(\xi \geq -1\) (where the wall density is finite); combined with the in-support bound, this gives the example prior’s lower limit \(\max(-1,\ -\sigma/(\max(\text{data}) - \mu))\).
Cap \(\xi\) from above if moments must exist. When the application needs a finite mean or variance, bound the \(\xi\) prior above accordingly: \(\xi < 1\) (mean) or \(\xi < 1/2\) (variance).
Keep \(\mu\) fixed at the threshold. In a peaks-over-threshold fit \(\mu\) is chosen in advance, not inferred. Estimating it has two failure modes: proposals with \(\mu > \min(\text{data})\) put observations out of support, and the corner \(\mu \to \min(\text{data})\), \(\sigma \to 0\) has unbounded likelihood when \(\xi > n - 1\).
Implementation details
Numerical precision near the wall. As \(x\) nears the wall \(x = x_F\), the margin \(1 + \xi (x - \mu)/\sigma\) cancels toward \(0\). The log-density value stays accurate, but its gradient w.r.t. \(\sigma\) and \(\xi\) has relative error of order the machine epsilon divided by that margin. It stems from the finite precision of \(x\), and no reformulation of
logpavoids it.Difference from SciPy. For \(\xi < 0\) the wall \(x = x_F\) is treated as open:
logpreturns \(-\infty\) there. There is a finite limiting density for \(-1 \leq \xi < 0\) as \(x \to x_F^-\), and SciPy returns the limiting value. This endpoint carries zero probability mass, so the choice affects neither sampling nor integration.- __init__()#
Methods
__init__()dist([mu, sigma, xi])Create a tensor variable corresponding to the cls distribution.
icdf(mu, sigma, xi)logccdf(mu, sigma, xi)logcdf(mu, sigma, xi)logp(mu, sigma, xi)rv_op(mu, sigma, xi, *[, size, rng])support_point(size, mu, sigma, xi)