From 850aef9bea260cb8f5933a774b088b13739984a5 Mon Sep 17 00:00:00 2001 From: AtharvSharmaAI Date: Fri, 22 May 2026 09:51:08 +0530 Subject: [PATCH 1/2] add hyperactive tuner as importable --- skpro/model_selection/__init__.py | 3 +- skpro/model_selection/_hyperactive.py | 57 +++++++++++++++++++++++++++ skpro/registry/__init__.py | 2 + skpro/registry/_placeholder_rec.py | 41 +++++++++++++++++++ 4 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 skpro/model_selection/_hyperactive.py create mode 100644 skpro/registry/_placeholder_rec.py diff --git a/skpro/model_selection/__init__.py b/skpro/model_selection/__init__.py index 262fe9228..add6528d0 100644 --- a/skpro/model_selection/__init__.py +++ b/skpro/model_selection/__init__.py @@ -1,5 +1,6 @@ """Tuning and model selection.""" -__all__ = ["GridSearchCV", "RandomizedSearchCV"] +__all__ = ["GridSearchCV", "RandomizedSearchCV", "ProbaRegOptCV"] from skpro.model_selection._tuning import GridSearchCV, RandomizedSearchCV +from skpro.model_selection._hyperactive import ProbaRegOptCV diff --git a/skpro/model_selection/_hyperactive.py b/skpro/model_selection/_hyperactive.py new file mode 100644 index 000000000..00ecbb9ad --- /dev/null +++ b/skpro/model_selection/_hyperactive.py @@ -0,0 +1,57 @@ +# copyright: skpro developers, BSD-3-Clause License (see LICENSE file) +"""Hyperactive Search CV tuning for probabilistic regressors.""" + +from skpro.registry._placeholder_rec import _placeholder_record +from skpro.regression.base._delegate import _DelegatedProbaRegressor + +@_placeholder_record( + dependency="hyperactive", + import_path="hyperactive.integrations.skpro.ProbaRegOptCV" +) +class ProbaRegOptCV(_DelegatedProbaRegressor): + """Hyperparameter search cross-validation using Hyperactive tuner. + + Performs hyperparameter optimization of probabilistic regressors + using the hyperactive optimization backend. + """ + + _tags = { + "estimator_type": "regressor", + "capability:multioutput": True, + "capability:missing": True, + "python_dependencies": "hyperactive", + } + + def __init__( + self, + estimator, + optimizer, + cv=None, + scoring=None, + refit=True, + error_score=None, + backend=None, + backend_params=None, + ): + self.estimator = estimator + self.optimizer = optimizer + self.cv = cv + self.scoring = scoring + self.refit = refit + self.error_score = error_score + self.backend = backend + self.backend_params = backend_params + + super().__init__() + + # Clone tags from base estimator + tags_to_clone = [ + "capability:multioutput", + "capability:missing", + "capability:survival", + ] + self.clone_tags(estimator, tags_to_clone) + + def _fit(self, X, y, C=None): + """Fit stub placeholder.""" + pass diff --git a/skpro/registry/__init__.py b/skpro/registry/__init__.py index 7c641400b..90c2f62c1 100644 --- a/skpro/registry/__init__.py +++ b/skpro/registry/__init__.py @@ -10,6 +10,7 @@ ) from skpro.registry._craft import craft, deps, imports from skpro.registry._lookup import all_objects, all_tags +from skpro.registry._placeholder_rec import _placeholder_record from skpro.registry._scitype import scitype from skpro.registry._tags import ( OBJECT_TAG_LIST, @@ -33,4 +34,5 @@ "get_test_class_for_str", "imports", "scitype", + "_placeholder_record", ] diff --git a/skpro/registry/_placeholder_rec.py b/skpro/registry/_placeholder_rec.py new file mode 100644 index 000000000..52352b675 --- /dev/null +++ b/skpro/registry/_placeholder_rec.py @@ -0,0 +1,41 @@ +# copyright: skpro developers, BSD-3-Clause License (see LICENSE file) +"""Placeholder registry utilities for optional soft dependencies.""" + +import importlib +from functools import wraps + +def _placeholder_record(dependency, import_path): + """Decorator to mark a class as a placeholder for a soft dependency. + + If the soft dependency is installed, the class is transparently + replaced with the actual class from the external package. + If it is not installed, the stub class is returned. Any attempt + to instantiate it will raise an ImportError explaining how to + install the soft dependency. + """ + def decorator(cls): + from skbase.utils.dependencies import _check_soft_dependencies + + # Check if the soft dependency is installed in the environment + if _check_soft_dependencies(dependency, severity="none"): + try: + module_path, class_name = import_path.rsplit(".", 1) + module = importlib.import_module(module_path) + real_class = getattr(module, class_name) + return real_class + except (ImportError, AttributeError): + pass + + # If not installed, wrap __init__ to raise a clear soft-dependency error + original_init = cls.__init__ + + @wraps(original_init) + def new_init(self, *args, **kwargs): + from skbase.utils.dependencies import _check_soft_dependencies + _check_soft_dependencies(dependency, severity="error", obj=self) + original_init(self, *args, **kwargs) + + cls.__init__ = new_init + return cls + + return decorator From 8160ebdb97a93cb24dff9da6e86af8fa7e1663ce Mon Sep 17 00:00:00 2001 From: Atharv Sharma Date: Sun, 31 May 2026 19:13:16 +0530 Subject: [PATCH 2/2] Update _hyperactive.py --- skpro/model_selection/_hyperactive.py | 1 + 1 file changed, 1 insertion(+) diff --git a/skpro/model_selection/_hyperactive.py b/skpro/model_selection/_hyperactive.py index 00ecbb9ad..f20f3595c 100644 --- a/skpro/model_selection/_hyperactive.py +++ b/skpro/model_selection/_hyperactive.py @@ -20,6 +20,7 @@ class ProbaRegOptCV(_DelegatedProbaRegressor): "capability:multioutput": True, "capability:missing": True, "python_dependencies": "hyperactive", + "tests:vm": True, } def __init__(