Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
6 changes: 6 additions & 0 deletions .all-contributorsrc
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,12 @@
"bug",
"doc"
]
},
{
"login": "paramsureliya",
"name": "Param Sureliya",
"profile": "https://github.com/paramsureliya",
"contributions": ["code"]
}
]
}
130 changes: 130 additions & 0 deletions skpro/regression/_dist_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# copyright: skpro developers, BSD-3-Clause License (see LICENSE file)
"""Distribution string normalisation utility for skpro regressors.

Provides ``_normalize_dist_str``, which maps all known string aliases for a
probability distribution to the canonical capitalized class name used in skpro
(e.g. ``"gaussian"`` -> ``"Normal"``, ``"t"`` -> ``"TDistribution"``).

Every probabilistic regressor adapter should call this before its own internal
string -> object mapping so that users can pass any reasonable alias and have it
work uniformly across regressors and in GridSearchCV / RandomizedSearchCV.
"""

_DIST_ALIAS_MAP: dict[str, str] = {
# Normal / Gaussian
"normal": "Normal",
"gaussian": "Normal",
"norm": "Normal",
# Laplace
"laplace": "Laplace",
"double_exponential": "Laplace",
# LogNormal
"lognormal": "LogNormal",
"log_normal": "LogNormal",
"log-normal": "LogNormal",
"log normal": "LogNormal",
# TDistribution
"tdistribution": "TDistribution",
"t_distribution": "TDistribution",
"t-distribution": "TDistribution",
"t": "TDistribution",
"student_t": "TDistribution",
"studentt": "TDistribution",
"student-t": "TDistribution",
# Poisson
"poisson": "Poisson",
# Exponential
"exponential": "Exponential",
"exp": "Exponential",
# Gamma
"gamma": "Gamma",
# Beta
"beta": "Beta",
# Weibull
"weibull": "Weibull",
# Cauchy
"cauchy": "Cauchy",
# Binomial
"binomial": "Binomial",
"binom": "Binomial",
# NegativeBinomial
"negativebinomial": "NegativeBinomial",
"negative_binomial": "NegativeBinomial",
"negative.binomial": "NegativeBinomial",
"negbinomial": "NegativeBinomial",
"negbin": "NegativeBinomial",
"neg_binomial": "NegativeBinomial",
# InverseGaussian
"inversegaussian": "InverseGaussian",
"inverse_gaussian": "InverseGaussian",
"inverse.gaussian": "InverseGaussian",
"inv_gaussian": "InverseGaussian",
# Tweedie
"tweedie": "Tweedie",
# Logistic / SinhLogistic (QPD inner distributions used by CyclicBoosting)
"logistic": "Logistic",
"sinhlogistic": "SinhLogistic",
"sinh_logistic": "SinhLogistic",
"sinh-logistic": "SinhLogistic",
}


def _normalize_dist_str(dist: str) -> str:
"""Normalize a distribution string to the canonical capitalized class name.

Maps every known alias (case-insensitive) to the capitalized skpro class
name, e.g.::

_normalize_dist_str("gaussian") -> "Normal"
_normalize_dist_str("t") -> "TDistribution"
_normalize_dist_str("lognormal") -> "LogNormal"
_normalize_dist_str("Normal") -> "Normal" # already canonical

Non-string inputs (e.g. a distribution class or object) are returned
unchanged so callers do not need to guard separately.

Unknown strings emit a ``UserWarning`` and are returned as-is to preserve
backward-compatibility with any existing library-specific aliases.

Parameters
----------
dist : str
Distribution name in any accepted format.

Returns
-------
str
Canonical distribution name (capitalised class name in skpro).

Examples
--------
>>> from skpro.regression._dist_utils import _normalize_dist_str
>>> _normalize_dist_str("gaussian")
'Normal'
>>> _normalize_dist_str("lognormal")
'LogNormal'
>>> _normalize_dist_str("t")
'TDistribution'
>>> _normalize_dist_str("Normal")
'Normal'
"""
if not isinstance(dist, str):
return dist

lower = dist.lower()

# 1. Direct alias lookup (handles the vast majority of cases)
if lower in _DIST_ALIAS_MAP:
return _DIST_ALIAS_MAP[lower]

# 2. Unknown — warn but do not raise (preserves backward-compatibility)
import warnings

warnings.warn(
f"Distribution string '{dist}' is not recognised by _normalize_dist_str "
f"and will be passed through unchanged. If this is intentional, consider "
f"adding it to _DIST_ALIAS_MAP in skpro/regression/_dist_utils.py.",
UserWarning,
stacklevel=2,
)
return dist
25 changes: 18 additions & 7 deletions skpro/regression/adapters/ngboost/_ngboost_proba.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

__author__ = ["ShreeshaM07"]

from skpro.regression._dist_utils import _normalize_dist_str


class NGBoostAdapter:
"""Adapter to interconvert NGBoost and skpro BaseDistributions.
Expand Down Expand Up @@ -34,6 +36,9 @@ def _dist_to_ngboost_instance(self, dist, survival=False):
"""
from ngboost.distns import Exponential, Laplace, LogNormal, Normal, Poisson, T

# normalize aliases like "gaussian" -> "Normal", "lognormal" -> "LogNormal"
dist = _normalize_dist_str(dist)

ngboost_dists = {
"Normal": Normal,
"Laplace": Laplace,
Expand Down Expand Up @@ -77,6 +82,9 @@ def _ngb_skpro_dist_params(
# Normal, Laplace, TDistribution and Poisson have not yet
# been implemented for Survival analysis.

# normalize aliases so dict lookups below always use canonical names
dist = _normalize_dist_str(self.dist)

dist_params = {
"Normal": ["loc", "scale"],
"Laplace": ["loc", "scale"],
Expand All @@ -95,14 +103,14 @@ def _ngb_skpro_dist_params(
"Exponential": ["rate"],
}

if self.dist in dist_params and self.dist in skpro_params:
ngboost_params = dist_params[self.dist]
skp_params = skpro_params[self.dist]
if dist in dist_params and dist in skpro_params:
ngboost_params = dist_params[dist]
skp_params = skpro_params[dist]
for ngboost_param, skp_param in zip(ngboost_params, skp_params):
kwargs[skp_param] = pred_dist.params[ngboost_param]
if self.dist == "LogNormal" and ngboost_param == "scale":
if dist == "LogNormal" and ngboost_param == "scale":
kwargs[skp_param] = np.log(pred_dist.params[ngboost_param])
if self.dist == "Exponential" and ngboost_param == "scale":
if dist == "Exponential" and ngboost_param == "scale":
kwargs[skp_param] = 1 / pred_dist.params[ngboost_param]

kwargs[skp_param] = self._check_y(y=kwargs[skp_param])
Expand Down Expand Up @@ -132,6 +140,9 @@ def _ngb_dist_to_skpro(self, **kwargs):
from skpro.distributions.poisson import Poisson
from skpro.distributions.t import TDistribution

# normalize aliases so dict lookup uses the canonical name
dist = _normalize_dist_str(self.dist)

ngboost_dists = {
"Normal": Normal,
"Laplace": Laplace,
Expand All @@ -143,7 +154,7 @@ def _ngb_dist_to_skpro(self, **kwargs):

skpro_dist = None

if self.dist in ngboost_dists:
skpro_dist = ngboost_dists[self.dist](**kwargs)
if dist in ngboost_dists:
skpro_dist = ngboost_dists[dist](**kwargs)

return skpro_dist
22 changes: 12 additions & 10 deletions skpro/regression/ensemble/_ngboost.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Adapters to ngboost regressors with probabilistic components."""

# copyright: skpro developers, BSD-3-Clause License (see LICENSE file)

__author__ = ["ShreeshaM07"]
Expand All @@ -18,16 +19,17 @@ class NGBoostRegressor(BaseProbaRegressor, NGBoostAdapter):
Parameters
----------
dist : string , default = "Normal"
distribution that must be used for
probabilistic prediction.
Available distribution types

1. "Normal"
2. "Laplace"
3. "LogNormal"
4. "Poisson"
5. "TDistribution"
6. "Exponential"
Distribution for probabilistic prediction.
The canonical names are case-insensitive and common aliases are
accepted (e.g. ``"gaussian"`` and ``"normal"`` both map to
``"Normal"``). Available distributions:

1. ``"Normal"`` (aliases: ``"gaussian"``, ``"norm"``)
2. ``"Laplace"`` (alias: ``"laplace"``)
3. ``"LogNormal"`` (aliases: ``"lognormal"``, ``"log_normal"``)
4. ``"Poisson"`` (alias: ``"poisson"``)
5. ``"TDistribution"`` (aliases: ``"t"``, ``"student_t"``)
6. ``"Exponential"`` (aliases: ``"exponential"``, ``"exp"``)

score : string , default = "LogScore"
A score from ngboost.scores for LogScore
Expand Down
Loading