Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
8def2b7
ENH: Add BurrIII, BurrXII, FDist, FatigueLife, GeneralizedPareto, Lev…
arnavk23 Dec 23, 2025
8ec3b88
Merge branch 'sktime:main' into fix/issue-22-distributions-main
arnavk23 Dec 23, 2025
bc8d363
MAINT: Remove unused numpy imports from new distribution files (flake…
arnavk23 Dec 23, 2025
178238f
flake8
arnavk23 Dec 23, 2025
3561d60
DOC: Categorize new distributions correctly in API reference
arnavk23 Dec 23, 2025
0555734
flake8 - 2
arnavk23 Dec 23, 2025
498d2bb
Update distributions.rst
arnavk23 Dec 23, 2025
484ee6f
Fix property and attribute handling for new distributions; ensure all…
arnavk23 Dec 23, 2025
63f6e6e
Add missing docstrings to loc and scale property methods in Levy and …
arnavk23 Dec 23, 2025
15e4d0d
black
arnavk23 Dec 23, 2025
eed7422
fkiraly additons
arnavk23 Dec 24, 2025
a5f7912
formatting distributions
arnavk23 Dec 24, 2025
c999a65
formatting distributions - 2
arnavk23 Dec 24, 2025
15983fe
flake8
arnavk23 Dec 24, 2025
28a68dd
The custom test logic in the scipy adapter test now allows both np.in…
arnavk23 Dec 24, 2025
41d92c6
format
arnavk23 Dec 24, 2025
144e2ae
format
arnavk23 Dec 24, 2025
f1e7446
flake8
arnavk23 Dec 24, 2025
b080235
review changes to distribution implementations
arnavk23 Dec 27, 2025
dd4e821
refactor: improve distribution adapter tests and fix bugs in distribu…
arnavk23 Dec 27, 2025
017516a
refactoring burr_iii
arnavk23 Dec 27, 2025
0f669b8
format
arnavk23 Dec 27, 2025
f490585
var docstring
arnavk23 Dec 27, 2025
3673010
Allow nan for variance in distribution tests and treat nan/inf as equ…
arnavk23 Dec 30, 2025
4dc727a
DOC: Fix pydocstyle D205 in BurrIII._var docstring (add blank line be…
arnavk23 Dec 30, 2025
e3657f4
black
arnavk23 Dec 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions docs/source/api_reference/distributions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,17 @@ Continuous support - non-negative reals

Alpha
Beta
BurrIII
BurrXII
ChiSquared
Exponential
Erlang
FatigueLife
FDist
Fisk
Gamma
GeneralizedPareto
Levy
LogGamma
HalfCauchy
HalfLogistic
Expand All @@ -67,6 +73,7 @@ Continuous support - non-negative reals
InverseGaussian
LogLaplace
Pareto
TruncatedPareto
Weibull


Expand All @@ -84,6 +91,7 @@ Integer support
Hurdle
NegativeBinomial
Poisson
Skellam

Non-parametric and empirical distributions
------------------------------------------
Expand Down
16 changes: 16 additions & 0 deletions skpro/distributions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,18 @@
"Alpha",
"Beta",
"Binomial",
"BurrIII",
"BurrXII",
"ChiSquared",
"Delta",
"Empirical",
"Erlang",
"Exponential",
"FDist",
"FatigueLife",
"Fisk",
"Gamma",
"GeneralizedPareto",
"LogGamma",
"Geometric",
"HalfCauchy",
Expand All @@ -26,6 +31,7 @@
"Histogram",
"Laplace",
"LeftTruncated",
"Levy",
"Logistic",
"LogLaplace",
"LogNormal",
Expand All @@ -40,26 +46,33 @@
"QPD_B",
"QPD_U",
"QPD_Johnson",
"Skellam",
"SkewNormal",
"TDistribution",
"TransformedDistribution",
"TruncatedDistribution",
"TruncatedNormal",
"TruncatedPareto",
"Uniform",
"Weibull",
]

from skpro.distributions.alpha import Alpha
from skpro.distributions.beta import Beta
from skpro.distributions.binomial import Binomial
from skpro.distributions.burr_iii import BurrIII
from skpro.distributions.burr_xii import BurrXII
from skpro.distributions.chi_squared import ChiSquared
from skpro.distributions.compose import IID
from skpro.distributions.delta import Delta
from skpro.distributions.empirical import Empirical
from skpro.distributions.erlang import Erlang
from skpro.distributions.exponential import Exponential
from skpro.distributions.f_dist import FDist
from skpro.distributions.fatigue_life import FatigueLife
from skpro.distributions.fisk import Fisk
from skpro.distributions.gamma import Gamma
from skpro.distributions.gen_pareto import GeneralizedPareto
from skpro.distributions.geometric import Geometric
from skpro.distributions.halfcauchy import HalfCauchy
from skpro.distributions.halflogistic import HalfLogistic
Expand All @@ -70,6 +83,7 @@
from skpro.distributions.inversegaussian import InverseGaussian
from skpro.distributions.laplace import Laplace
from skpro.distributions.left_truncated import LeftTruncated
from skpro.distributions.levy import Levy
from skpro.distributions.loggamma import LogGamma
from skpro.distributions.logistic import Logistic
from skpro.distributions.loglaplace import LogLaplace
Expand All @@ -82,10 +96,12 @@
from skpro.distributions.poisson import Poisson
from skpro.distributions.qpd import QPD_B, QPD_S, QPD_U, QPD_Johnson
from skpro.distributions.qpd_empirical import QPD_Empirical
from skpro.distributions.skellam import Skellam
from skpro.distributions.skew_normal import SkewNormal
from skpro.distributions.t import TDistribution
from skpro.distributions.trafo import TransformedDistribution
from skpro.distributions.truncated import TruncatedDistribution
from skpro.distributions.truncated_normal import TruncatedNormal
from skpro.distributions.truncated_pareto import TruncatedPareto
from skpro.distributions.uniform import Uniform
from skpro.distributions.weibull import Weibull
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,14 @@ def test_method_no_params(self, object_instance, method, scipy_method):

scipy_res = getattr(scipy_obj, scipy_method)(*params[0], **params[1])

# Treat (nan, nan) and (inf, inf) as equal for scalar results
import numpy as np

if np.isscalar(res) and np.isscalar(scipy_res):
if np.isnan(res) and np.isnan(scipy_res):
return
if np.isinf(res) and np.isinf(scipy_res) and (res > 0) == (scipy_res > 0):
return
assert np.allclose(res, scipy_res)

@pytest.mark.parametrize("method,scipy_method", METHOD_TESTS["X_PARAMS"])
Expand Down
67 changes: 67 additions & 0 deletions skpro/distributions/burr_iii.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"""Burr III probability distribution for skpro."""

from scipy.stats import burr12, rv_continuous

from skpro.distributions.adapters.scipy import _ScipyAdapter


class BurrIII(_ScipyAdapter):
r"""Burr III probability distribution.

The Burr III distribution is a continuous probability distribution with two
parameters: shape parameter $c > 0$ and scale parameter $s > 0$.
Its probability density function (PDF) is:

.. math::
f(x; c, s) = \frac{c}{s} \left(\frac{x}{s}\right)^{-c-1}
\left[1 + \left(\frac{x}{s}\right)^{-c}\right]^{-2}, \quad x > 0

Parameters
----------
c : float
Shape parameter
scale : float
Scale parameter
"""

_tags = {
"authors": ["arnavk23"],
"distr:measuretype": "continuous",
"capabilities:exact": ["mean", "var", "pdf", "log_pdf", "cdf", "ppf"],
"broadcast_init": "on",
}

def __init__(self, c, scale=1.0, index=None, columns=None):
self.c = c
self.scale = scale
super().__init__(index=index, columns=columns)

def _get_scipy_object(self) -> rv_continuous:
return burr12

def _get_scipy_param(self):
c = self._bc_params["c"]
scale = self._bc_params["scale"]
# Burr III is Burr XII with d=1
return [], {"c": c, "d": 1, "scale": scale}

def _var(self):
"""Return the variance of the Burr III distribution.

Variance is infinite if c < 2, nan if c == 2, else finite.
"""
import numpy as np

c = self.c if hasattr(self, "c") else self._bc_params["c"]
if c < 2:
return np.inf
if c == 2:
return np.nan
return super()._var()

@classmethod
def get_test_params(cls, parameter_set="default"):
"""Return test parameters for BurrIII."""
params1 = {"c": 2.0, "scale": 1.0}
params2 = {"c": 3.0, "scale": 2.0}
return [params1, params2]
86 changes: 86 additions & 0 deletions skpro/distributions/burr_xii.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
"""Burr XII probability distribution for skpro."""

from scipy.stats import burr12, rv_continuous

from skpro.distributions.adapters.scipy import _ScipyAdapter


class BurrXII(_ScipyAdapter):
r"""Burr XII probability distribution.

The Burr XII distribution is a continuous probability distribution with two
shape parameters $c > 0$, $d > 0$ and a scale parameter $s > 0$.
Its probability density function (PDF) is:

.. math::
f(x; c, d, s) = \frac{c d}{s} \left(\frac{x}{s}\right)^{c-1}
\left[1 + \left(\frac{x}{s}\right)^c\right]^{-d-1}, \quad x > 0

Parameters
----------
c : float
Shape parameter
d : float
Shape parameter
scale : float
Scale parameter
"""

_tags = {
"authors": ["arnavk23"],
"distr:measuretype": "continuous",
"capabilities:exact": ["mean", "var", "pdf", "log_pdf", "cdf", "ppf"],
"broadcast_init": "on",
}

def __init__(self, c, d, scale=1.0, index=None, columns=None):
self.c = c
self.d = d
self.scale = scale
super().__init__(index=index, columns=columns)

def _get_scipy_object(self) -> rv_continuous:
return burr12

def _get_scipy_param(self):
c = self._bc_params["c"]
d = self._bc_params["d"]
scale = self._bc_params["scale"]
return [], {"c": c, "d": d, "scale": scale}

def _pdf(self, x):
c = self._bc_params["c"]
d = self._bc_params["d"]
scale = self._bc_params["scale"]
return burr12.pdf(x, c, d, scale=scale)

def _cdf(self, x):
c = self._bc_params["c"]
d = self._bc_params["d"]
scale = self._bc_params["scale"]
return burr12.cdf(x, c, d, scale=scale)

def _ppf(self, p):
c = self._bc_params["c"]
d = self._bc_params["d"]
scale = self._bc_params["scale"]
return burr12.ppf(p, c, d, scale=scale)

def _mean(self):
c = self._bc_params["c"]
d = self._bc_params["d"]
scale = self._bc_params["scale"]
return burr12.mean(c, d, scale=scale)

def _var(self):
c = self._bc_params["c"]
d = self._bc_params["d"]
scale = self._bc_params["scale"]
return burr12.var(c, d, scale=scale)

@classmethod
def get_test_params(cls, parameter_set="default"):
"""Return test parameters for BurrXII."""
params1 = {"c": 2.0, "d": 3.0, "scale": 1.0}
params2 = {"c": 4.0, "d": 2.0, "scale": 2.0}
return [params1, params2]
82 changes: 82 additions & 0 deletions skpro/distributions/f_dist.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
"""F probability distribution for skpro."""

from scipy.stats import f, rv_continuous

from skpro.distributions.adapters.scipy import _ScipyAdapter


class FDist(_ScipyAdapter):
r"""F (Fisher-Snedecor) probability distribution.

The F-distribution (Fisher-Snedecor distribution) is a continuous probability
distribution that arises frequently as the null distribution of a test statistic,
especially in ANOVA. It is parameterized by two degrees of freedom parameters
$d_1 > 0$ (numerator) and $d_2 > 0$ (denominator). Its probability density
function (PDF) is:

.. math::
f(x; d_1, d_2) =
\frac{\sqrt{\frac{(d_1 x)^{d_1} d_2^{d_2}}{(d_1 x + d_2)^{d_1 + d_2}}}}
{x \cdot B\left(\frac{d_1}{2}, \frac{d_2}{2}\right)}, \quad x > 0

where $B$ is the beta function.

Parameters
----------
dfn : float
Degrees of freedom numerator
dfd : float
Degrees of freedom denominator
"""

_tags = {
"authors": ["arnavk23"],
"distr:measuretype": "continuous",
"capabilities:exact": ["mean", "var", "pdf", "log_pdf", "cdf", "ppf"],
"broadcast_init": "on",
}

def __init__(self, dfn, dfd, index=None, columns=None):
self.dfn = dfn
self.dfd = dfd
super().__init__(index=index, columns=columns)

def _get_scipy_object(self) -> rv_continuous:
return f

def _get_scipy_param(self):
dfn = self._bc_params["dfn"]
dfd = self._bc_params["dfd"]
return [], {"dfn": dfn, "dfd": dfd}

def _pdf(self, x):
dfn = self._bc_params["dfn"]
dfd = self._bc_params["dfd"]
return f.pdf(x, dfn, dfd)

def _cdf(self, x):
dfn = self._bc_params["dfn"]
dfd = self._bc_params["dfd"]
return f.cdf(x, dfn, dfd)

def _ppf(self, p):
dfn = self._bc_params["dfn"]
dfd = self._bc_params["dfd"]
return f.ppf(p, dfn, dfd)

def _mean(self):
dfn = self._bc_params["dfn"]
dfd = self._bc_params["dfd"]
return f.mean(dfn, dfd)

def _var(self):
dfn = self._bc_params["dfn"]
dfd = self._bc_params["dfd"]
return f.var(dfn, dfd)

@classmethod
def get_test_params(cls, parameter_set="default"):
"""Return test parameters for FDist."""
params1 = {"dfn": 5.0, "dfd": 2.0}
params2 = {"dfn": 10.0, "dfd": 5.0}
return [params1, params2]
Loading