pod.infer_best_distribution
infer_best_distribution(residuals, X, bandwidth)Selects the best statistical distribution for the standardized residuals using AIC.
The residuals are divided by their local standard deviation (predict_local_std) to give z-scores, which are fitted by maximum likelihood to each of 12 candidate distributions: Normal, Gumbel (right and left), Weibull (min and max), Gamma, Exponential, Logistic, Laplace, Student’s t, Beta and Uniform ([M25] Sec. 2f). The fit with the lowest AIC wins.
[digiqual] Bounded-support families (Weibull, Gamma, Exponential, Beta, Uniform) have a free location parameter, so maximum likelihood can push a support endpoint right up against the most extreme z-score. Such a degenerate fit can win on AIC yet give PoD values of exactly 0 or 1 just outside the observed range, and kinked a90/95 values. A fit is therefore only accepted if its support contains every z-score with a margin of 5 % of their range, and its log-likelihood is finite. [M25] used UQLab’s inference, which similarly excludes unsuitable distributions.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| residuals | np.ndarray | Raw residuals from the mean model. | required |
| X | np.ndarray | Input locations for the residuals. | required |
| bandwidth | float | Bandwidth used for local standardization. | required |
Returns
| Name | Type | Description |
|---|---|---|
| tuple[str, tuple] | tuple[str, tuple]: - best_name: The SciPy name of the best-fitting distribution (e.g., ‘norm’). - best_params: The fitted parameters for that distribution (e.g., loc, scale). |
Examples
import numpy as np
from digiqual.pod import infer_best_distribution
X = np.linspace(0, 10, 200)
residuals = np.random.default_rng(0).gumbel(0, 1 + 0.1 * X)
dist_name, dist_params = infer_best_distribution(residuals, X, bandwidth=0.5)
print(f"Best distribution: {dist_name}")