From c05c537cad92da035d207cfc3ee5b9c46db712cd Mon Sep 17 00:00:00 2001 From: tpvasconcelos Date: Sat, 16 Dec 2023 19:04:14 +0000 Subject: [PATCH 01/12] [AUTOMATED] update CONTRIBUTORS.md --- CONTRIBUTORS.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 02b377ccc0a..28657532321 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -2,7 +2,7 @@ Contributors ============ -[![All Contributors](https://img.shields.io/badge/all_contributors-241-orange.svg)](#contributors) +[![All Contributors](https://img.shields.io/badge/all_contributors-242-orange.svg)](#contributors) This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! @@ -214,6 +214,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Piyush Gade
Piyush Gade

💻 👀 + Poruri Sai Rahul
Poruri Sai Rahul

📖 Pranav Prajapati
Pranav Prajapati

💻 ⚠️ Pulkit Verma
Pulkit Verma

📖 Quaterion
Quaterion

🐛 @@ -221,9 +222,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Ramon Bussing
Ramon Bussing

📖 💻 RavenRudi
RavenRudi

💻 Rick van Hattem
Rick van Hattem

🚇 - Rishabh Bali
Rishabh Bali

💻 + Rishabh Bali
Rishabh Bali

💻 Rishi Kumar Ray
Rishi Kumar Ray

🚇 Riya Elizabeth John
Riya Elizabeth John

💻 ⚠️ 📖 Roman Lutz
Roman Lutz

📖 @@ -232,9 +233,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Sagar Mishra
Sagar Mishra

⚠️ Sajaysurya Ganesh
Sajaysurya Ganesh

💻 📖 🎨 💡 🤔 ⚠️ Sami Alavi
Sami Alavi

💻 🚧 - Saransh Chopra
Saransh Chopra

📖 🚇 + Saransh Chopra
Saransh Chopra

📖 🚇 Satya Prakash Pattnaik
Satya Prakash Pattnaik

📖 Saurabh Dasgupta
Saurabh Dasgupta

💻 Sebastiaan Koel
Sebastiaan Koel

💻 📖 @@ -243,9 +244,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Shivansh Subramanian
Shivansh Subramanian

📖 💻 Solomon Botchway
Solomon Botchway

🚧 Stanislav Khrapov
Stanislav Khrapov

💻 - Svea Marie Meyer
Svea Marie Meyer

📖 💻 + Svea Marie Meyer
Svea Marie Meyer

📖 💻 TNTran92
TNTran92

💻 Taisei Yamamoto
Taisei Yamamoto

💻 Taiwo Owoseni
Taiwo Owoseni

💻 @@ -254,9 +255,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Thomas Buckley-Houston
Thomas Buckley-Houston

🐛 Tom Xu
Tom Xu

💻 📖 Tomas P. de Vasconcelos
Tomas P. de Vasconcelos

🐛 💻 - Tomasz Chodakowski
Tomasz Chodakowski

💻 📖 🐛 + Tomasz Chodakowski
Tomasz Chodakowski

💻 📖 🐛 Tony Bagnall
Tony Bagnall

💻 💼 📖 🎨 📋 🔍 🤔 📆 💬 👀 📢 🔣 Utsav Kumar Tiwari
Utsav Kumar Tiwari

💻 📖 Vasudeva Kilaru
Vasudeva Kilaru

💻 📖 @@ -265,9 +266,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Vyomkesh Vyas
Vyomkesh Vyas

💻 📖 💡 ⚠️ William Templier
William Templier

📖 William Zheng
William Zheng

💻 ⚠️ - Yair Beer
Yair Beer

💻 + Yair Beer
Yair Beer

💻 Yann Hallouard
Yann Hallouard

💻 ⚠️ Yash Lamba
Yash Lamba

💻 Yi-Xuan Xu
Yi-Xuan Xu

💻 ⚠️ 🚧 📖 @@ -276,9 +277,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d aa25desh
aa25desh

💻 🐛 abandus
abandus

🤔 💻 adoherty21
adoherty21

🐛 - bethrice44
bethrice44

🐛 💻 👀 ⚠️ + bethrice44
bethrice44

🐛 💻 👀 ⚠️ big-o
big-o

💻 ⚠️ 🎨 🤔 👀 🧑‍🏫 bobbys
bobbys

💻 brett koonce
brett koonce

📖 @@ -287,9 +288,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d chrisholder
chrisholder

💻 ⚠️ 📖 🎨 💡 danbartl
danbartl

🐛 💻 👀 📢 ⚠️ 📹 hamzahiqb
hamzahiqb

🚇 - hiqbal2
hiqbal2

📖 + hiqbal2
hiqbal2

📖 jesellier
jesellier

💻 jschemm
jschemm

💻 kkoziara
kkoziara

💻 🐛 @@ -298,9 +299,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d pabworks
pabworks

💻 ⚠️ patiently pending world peace
patiently pending world peace

💻 raishubham1
raishubham1

📖 - simone-pignotti
simone-pignotti

💻 🐛 + simone-pignotti
simone-pignotti

💻 🐛 sophijka
sophijka

📖 🚧 sri1419
sri1419

💻 tensorflow-as-tf
tensorflow-as-tf

💻 From b9a96051fa94948dd04927a899cbedd9a2187eb9 Mon Sep 17 00:00:00 2001 From: Tomas Pereira de Vasconcelos Date: Sun, 17 Dec 2023 01:08:23 +0000 Subject: [PATCH 02/12] Add new `FunctionParamFitter` parameter estimator --- sktime/param_est/compose.py | 120 +++++++++++++++++++++++++++++++++++- 1 file changed, 119 insertions(+), 1 deletion(-) diff --git a/sktime/param_est/compose.py b/sktime/param_est/compose.py index 7c4d3d8e47b..b24e7b3db2a 100644 --- a/sktime/param_est/compose.py +++ b/sktime/param_est/compose.py @@ -1,12 +1,13 @@ """Composition involving parameter estimators.""" # copyright: sktime developers, BSD-3-Clause License (see LICENSE file) from sktime.base import _HeterogenousMetaEstimator +from sktime.datatypes import ALL_TIME_SERIES_MTYPES from sktime.param_est.base import BaseParamFitter from sktime.transformations.base import BaseTransformer from sktime.transformations.compose import TransformerPipeline __author__ = ["fkiraly"] -__all__ = ["ParamFitterPipeline"] +__all__ = ["ParamFitterPipeline", "FunctionParamFitter"] # we ensure that internally we convert to pandas for now @@ -301,3 +302,120 @@ def get_test_params(cls, parameter_set="default"): params = params + [{"transformers": [t1, t2], "param_est": p}] return params + + +class FunctionParamFitter(BaseParamFitter): + r"""Constructs a parameter fitter from an arbitrary callable. + + A FunctionParamFitter forwards its X argument to a user-defined + function (or callable object) and sets the result of this function + to the ``param`` attribute. This can be useful for stateless + estimators such as simple conditional parameter selectors. + + Note: If a lambda function is used as the ``func``, then the + resulting estimator will not be pickleable. + + Parameters + ---------- + param : str + The name of the parameter to set. + func : callable (X: X_type, **kwargs) -> Any + The callable to use for the parameter estimation. This will be + passed the same arguments as estimator, with args and kwargs + forwarded. + + See Also + -------- + sktime.param_est.plugin.PluginParamsForecaster : + Plugs parameters from a parameter estimator into a forecaster. + sktime.forecasting.compose.MultiplexForecaster : + MultiplexForecaster for selecting among different models. + + Examples + -------- + This class could be used to contruct a parameter estimator that + selects a forecaster based on the input data's length. The + selected forecaster can be stored in the `selected_forecaster_` + attribute, which can be then passed down to a + ``MultiplexForecaster`` via a ``PluginParamsForecaster``. + + >>> import numpy as np + >>> param_est = FunctionParamFitter( + ... param="selected_forecaster", + ... func=( + ... lambda X, threshold: "naive-seasonal" + ... if len(X) >= threshold + ... else "naive-last" + ... ), + ... kw_args={"threshold": 7}, + ... ) + >>> param_est.fit(np.asarray([1, 2, 3, 4])) + >>> param_est.selected_forecaster_ + 'naive-last' + >>> param_est.fit(np.asarray([1, 2, 3, 4, 5, 6, 7])) + >>> param_est.selected_forecaster_ + 'naive-seasonal' + """ + + _tags = { + "X_inner_mtype": ALL_TIME_SERIES_MTYPES, + "scitype:X": ["Series", "Panel", "Hierarchical"], + "capability:missing_values": True, + "capability:multivariate": False, + } + + def __init__(self, param, func, kw_args=None, X_type=None): + self.param = param + self.func = func + self.kw_args = kw_args + self.X_type = X_type + super().__init__() + + if X_type is not None: + self.set_tags(X_inner_mtype=X_type) + + def _fit(self, X): + """Fit estimator and estimate parameters. + + private _fit containing the core logic, called from fit + + Writes to self: + Sets fitted model attributes ending in "_". + + Parameters + ---------- + X : guaranteed to be of a type in self.get_tag("X_inner_mtype") + Time series to which to fit the estimator. + + Returns + ------- + self : reference to self + """ + param = self.param.rstrip("_") + "_" + setattr(self, param, self.func(X, **(self.kw_args or {}))) + return self + + @classmethod + def get_test_params(cls, parameter_set="default"): + """Return testing parameter settings for the estimator. + + Parameters + ---------- + parameter_set : str, default="default" + Name of the set of test parameters to return, for use in tests. If no + special parameters are defined for a value, will return `"default"` set. + There are no reserved values for parameter estimators. + + Returns + ------- + params : dict or list of dict, default = {} + Parameters to create testing instances of the class + Each dict are parameters to construct an "interesting" test instance, i.e., + `MyClass(**params)` or `MyClass(**params[i])` creates a valid test instance. + `create_test_instance` uses the first (or only) dictionary in `params` + """ + params = [ + {"param": "param", "func": lambda X: "foo"}, + {"param": "param", "func": lambda X, kwarg: "foo", "kw_args": {"kwarg": 1}}, + ] + return params From de919040feda945a01b02495fef7f36f95fc60d1 Mon Sep 17 00:00:00 2001 From: Tomas Pereira de Vasconcelos Date: Sun, 17 Dec 2023 01:13:01 +0000 Subject: [PATCH 03/12] Update `FunctionTransformer` docstring To make it more consistent with the new `FunctionParamFitter` class --- sktime/transformations/series/func_transform.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sktime/transformations/series/func_transform.py b/sktime/transformations/series/func_transform.py index 0d853141d9a..d8ed5232413 100644 --- a/sktime/transformations/series/func_transform.py +++ b/sktime/transformations/series/func_transform.py @@ -18,12 +18,12 @@ class FunctionTransformer(BaseTransformer): r"""Constructs a transformer from an arbitrary callable. A FunctionTransformer forwards its y (and optionally X) arguments to a - user-defined function or function object and returns the result of this + user-defined function (or callable object) and returns the result of this function. This is useful for stateless transformations such as taking the log of frequencies, doing custom scaling, etc. - Note: If a lambda is used as the function, then the resulting - transformer will not be pickleable. + Note: If a lambda function is used as the ``func``, then the + resulting transformer will not be pickleable. Parameters ---------- From 4a9425a977df798f65484c6726413b330c589a10 Mon Sep 17 00:00:00 2001 From: Tomas Pereira de Vasconcelos Date: Sun, 17 Dec 2023 01:13:46 +0000 Subject: [PATCH 04/12] Simplify the BaseParamFitter's `_get_fitted_params()` --- sktime/param_est/base.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sktime/param_est/base.py b/sktime/param_est/base.py index d1a430e7603..9e2069ef11c 100644 --- a/sktime/param_est/base.py +++ b/sktime/param_est/base.py @@ -396,8 +396,8 @@ def _get_fitted_params(self): """ # default retrieves all self attributes ending in "_" # and returns them with keys that have the "_" removed - fitted_params = [attr for attr in dir(self) if attr.endswith("_")] - fitted_params = [x for x in fitted_params if not x.startswith("_")] - fitted_param_dict = {p[:-1]: getattr(self, p) for p in fitted_params} - - return fitted_param_dict + return { + attr[:-1]: getattr(self, attr) + for attr in dir(self) + if attr.endswith("_") and not attr.startswith("_") + } From 13899f93a690e3ed89aa7de19390b72ad551c508 Mon Sep 17 00:00:00 2001 From: Tomas Pereira de Vasconcelos Date: Sun, 17 Dec 2023 20:05:45 +0000 Subject: [PATCH 05/12] Revert changes to `_get_fitted_params()` --- sktime/param_est/base.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sktime/param_est/base.py b/sktime/param_est/base.py index 9e2069ef11c..d1a430e7603 100644 --- a/sktime/param_est/base.py +++ b/sktime/param_est/base.py @@ -396,8 +396,8 @@ def _get_fitted_params(self): """ # default retrieves all self attributes ending in "_" # and returns them with keys that have the "_" removed - return { - attr[:-1]: getattr(self, attr) - for attr in dir(self) - if attr.endswith("_") and not attr.startswith("_") - } + fitted_params = [attr for attr in dir(self) if attr.endswith("_")] + fitted_params = [x for x in fitted_params if not x.startswith("_")] + fitted_param_dict = {p[:-1]: getattr(self, p) for p in fitted_params} + + return fitted_param_dict From 1b619c718d151f322a27dc7bd36db1bb28f2aa4e Mon Sep 17 00:00:00 2001 From: Tomas Pereira de Vasconcelos Date: Sun, 17 Dec 2023 20:11:32 +0000 Subject: [PATCH 06/12] Revert changes in docstring --- sktime/transformations/series/func_transform.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sktime/transformations/series/func_transform.py b/sktime/transformations/series/func_transform.py index d8ed5232413..0d853141d9a 100644 --- a/sktime/transformations/series/func_transform.py +++ b/sktime/transformations/series/func_transform.py @@ -18,12 +18,12 @@ class FunctionTransformer(BaseTransformer): r"""Constructs a transformer from an arbitrary callable. A FunctionTransformer forwards its y (and optionally X) arguments to a - user-defined function (or callable object) and returns the result of this + user-defined function or function object and returns the result of this function. This is useful for stateless transformations such as taking the log of frequencies, doing custom scaling, etc. - Note: If a lambda function is used as the ``func``, then the - resulting transformer will not be pickleable. + Note: If a lambda is used as the function, then the resulting + transformer will not be pickleable. Parameters ---------- From 6631e8426ceacecae9e303f282e195be6ccaa421 Mon Sep 17 00:00:00 2001 From: Tomas Pereira de Vasconcelos Date: Sun, 17 Dec 2023 20:19:35 +0000 Subject: [PATCH 07/12] Refactor `compose.py` module to `compose` package with `_func_fitter.py` and `_pipeline.py` modules --- sktime/param_est/compose/__init__.py | 7 + sktime/param_est/compose/_func_fitter.py | 124 +++++++++++++++++ .../{compose.py => compose/_pipeline.py} | 126 +----------------- 3 files changed, 136 insertions(+), 121 deletions(-) create mode 100644 sktime/param_est/compose/__init__.py create mode 100644 sktime/param_est/compose/_func_fitter.py rename sktime/param_est/{compose.py => compose/_pipeline.py} (73%) diff --git a/sktime/param_est/compose/__init__.py b/sktime/param_est/compose/__init__.py new file mode 100644 index 00000000000..10423cfb2b0 --- /dev/null +++ b/sktime/param_est/compose/__init__.py @@ -0,0 +1,7 @@ +"""Composition involving parameter estimators.""" +# copyright: sktime developers, BSD-3-Clause License (see LICENSE file) +from sktime.param_est.compose._func_fitter import FunctionParamFitter +from sktime.param_est.compose._pipeline import ParamFitterPipeline + +__author__ = ["fkiraly", "tpvasconcelos"] +__all__ = ["ParamFitterPipeline", "FunctionParamFitter"] diff --git a/sktime/param_est/compose/_func_fitter.py b/sktime/param_est/compose/_func_fitter.py new file mode 100644 index 00000000000..8757d3e0718 --- /dev/null +++ b/sktime/param_est/compose/_func_fitter.py @@ -0,0 +1,124 @@ +"""Implements FunctionParamFitter, a class to create custom parameter fitters.""" +# copyright: sktime developers, BSD-3-Clause License (see LICENSE file) +from sktime.datatypes import ALL_TIME_SERIES_MTYPES +from sktime.param_est.base import BaseParamFitter + +__author__ = ["tpvasconcelos"] +__all__ = ["FunctionParamFitter"] + + +class FunctionParamFitter(BaseParamFitter): + r"""Constructs a parameter fitter from an arbitrary callable. + + A FunctionParamFitter forwards its X argument to a user-defined + function (or callable object) and sets the result of this function + to the ``param`` attribute. This can be useful for stateless + estimators such as simple conditional parameter selectors. + + Note: If a lambda function is used as the ``func``, then the + resulting estimator will not be pickleable. + + Parameters + ---------- + param : str + The name of the parameter to set. + func : callable (X: X_type, **kwargs) -> Any + The callable to use for the parameter estimation. This will be + passed the same arguments as estimator, with args and kwargs + forwarded. + + See Also + -------- + sktime.param_est.plugin.PluginParamsForecaster : + Plugs parameters from a parameter estimator into a forecaster. + sktime.forecasting.compose.MultiplexForecaster : + MultiplexForecaster for selecting among different models. + + Examples + -------- + This class could be used to contruct a parameter estimator that + selects a forecaster based on the input data's length. The + selected forecaster can be stored in the `selected_forecaster_` + attribute, which can be then passed down to a + ``MultiplexForecaster`` via a ``PluginParamsForecaster``. + + >>> import numpy as np + >>> param_est = FunctionParamFitter( + ... param="selected_forecaster", + ... func=( + ... lambda X, threshold: "naive-seasonal" + ... if len(X) >= threshold + ... else "naive-last" + ... ), + ... kw_args={"threshold": 7}, + ... ) + >>> param_est.fit(np.asarray([1, 2, 3, 4])) + >>> param_est.selected_forecaster_ + 'naive-last' + >>> param_est.fit(np.asarray([1, 2, 3, 4, 5, 6, 7])) + >>> param_est.selected_forecaster_ + 'naive-seasonal' + """ + + _tags = { + "X_inner_mtype": ALL_TIME_SERIES_MTYPES, + "scitype:X": ["Series", "Panel", "Hierarchical"], + "capability:missing_values": True, + "capability:multivariate": False, + } + + def __init__(self, param, func, kw_args=None, X_type=None): + self.param = param + self.func = func + self.kw_args = kw_args + self.X_type = X_type + super().__init__() + + if X_type is not None: + self.set_tags(X_inner_mtype=X_type) + + def _fit(self, X): + """Fit estimator and estimate parameters. + + private _fit containing the core logic, called from fit + + Writes to self: + Sets fitted model attributes ending in "_". + + Parameters + ---------- + X : guaranteed to be of a type in self.get_tag("X_inner_mtype") + Time series to which to fit the estimator. + + Returns + ------- + self : reference to self + """ + param = self.param.rstrip("_") + "_" + setattr(self, param, self.func(X, **(self.kw_args or {}))) + return self + + @classmethod + def get_test_params(cls, parameter_set="default"): + """Return testing parameter settings for the estimator. + + Parameters + ---------- + parameter_set : str, default="default" + Name of the set of test parameters to return, for use in tests. If no + special parameters are defined for a value, will return `"default"` set. + There are no reserved values for parameter estimators. + + Returns + ------- + params : dict or list of dict, default = {} + Parameters to create testing instances of the class + Each dict are parameters to construct an "interesting" test instance, i.e., + `MyClass(**params)` or `MyClass(**params[i])` creates a valid test instance. + `create_test_instance` uses the first (or only) dictionary in `params` + """ + params = [ + {"param": "param", "func": lambda X: "foo"}, + {"param": "param", "func": lambda X, kwarg: "foo", "kw_args": {"kwarg": 1}}, + ] + return params diff --git a/sktime/param_est/compose.py b/sktime/param_est/compose/_pipeline.py similarity index 73% rename from sktime/param_est/compose.py rename to sktime/param_est/compose/_pipeline.py index b24e7b3db2a..bb1bff045b7 100644 --- a/sktime/param_est/compose.py +++ b/sktime/param_est/compose/_pipeline.py @@ -1,14 +1,15 @@ -"""Composition involving parameter estimators.""" +"""Implements ParamFitterPipeline. + +A class to create a pipeline of transformers and a parameter estimator. +""" # copyright: sktime developers, BSD-3-Clause License (see LICENSE file) from sktime.base import _HeterogenousMetaEstimator -from sktime.datatypes import ALL_TIME_SERIES_MTYPES from sktime.param_est.base import BaseParamFitter from sktime.transformations.base import BaseTransformer from sktime.transformations.compose import TransformerPipeline __author__ = ["fkiraly"] -__all__ = ["ParamFitterPipeline", "FunctionParamFitter"] - +__all__ = ["ParamFitterPipeline"] # we ensure that internally we convert to pandas for now SUPPORTED_MTYPES = ["pd.DataFrame", "pd.Series", "pd-multiindex", "pd_multiindex_hier"] @@ -302,120 +303,3 @@ def get_test_params(cls, parameter_set="default"): params = params + [{"transformers": [t1, t2], "param_est": p}] return params - - -class FunctionParamFitter(BaseParamFitter): - r"""Constructs a parameter fitter from an arbitrary callable. - - A FunctionParamFitter forwards its X argument to a user-defined - function (or callable object) and sets the result of this function - to the ``param`` attribute. This can be useful for stateless - estimators such as simple conditional parameter selectors. - - Note: If a lambda function is used as the ``func``, then the - resulting estimator will not be pickleable. - - Parameters - ---------- - param : str - The name of the parameter to set. - func : callable (X: X_type, **kwargs) -> Any - The callable to use for the parameter estimation. This will be - passed the same arguments as estimator, with args and kwargs - forwarded. - - See Also - -------- - sktime.param_est.plugin.PluginParamsForecaster : - Plugs parameters from a parameter estimator into a forecaster. - sktime.forecasting.compose.MultiplexForecaster : - MultiplexForecaster for selecting among different models. - - Examples - -------- - This class could be used to contruct a parameter estimator that - selects a forecaster based on the input data's length. The - selected forecaster can be stored in the `selected_forecaster_` - attribute, which can be then passed down to a - ``MultiplexForecaster`` via a ``PluginParamsForecaster``. - - >>> import numpy as np - >>> param_est = FunctionParamFitter( - ... param="selected_forecaster", - ... func=( - ... lambda X, threshold: "naive-seasonal" - ... if len(X) >= threshold - ... else "naive-last" - ... ), - ... kw_args={"threshold": 7}, - ... ) - >>> param_est.fit(np.asarray([1, 2, 3, 4])) - >>> param_est.selected_forecaster_ - 'naive-last' - >>> param_est.fit(np.asarray([1, 2, 3, 4, 5, 6, 7])) - >>> param_est.selected_forecaster_ - 'naive-seasonal' - """ - - _tags = { - "X_inner_mtype": ALL_TIME_SERIES_MTYPES, - "scitype:X": ["Series", "Panel", "Hierarchical"], - "capability:missing_values": True, - "capability:multivariate": False, - } - - def __init__(self, param, func, kw_args=None, X_type=None): - self.param = param - self.func = func - self.kw_args = kw_args - self.X_type = X_type - super().__init__() - - if X_type is not None: - self.set_tags(X_inner_mtype=X_type) - - def _fit(self, X): - """Fit estimator and estimate parameters. - - private _fit containing the core logic, called from fit - - Writes to self: - Sets fitted model attributes ending in "_". - - Parameters - ---------- - X : guaranteed to be of a type in self.get_tag("X_inner_mtype") - Time series to which to fit the estimator. - - Returns - ------- - self : reference to self - """ - param = self.param.rstrip("_") + "_" - setattr(self, param, self.func(X, **(self.kw_args or {}))) - return self - - @classmethod - def get_test_params(cls, parameter_set="default"): - """Return testing parameter settings for the estimator. - - Parameters - ---------- - parameter_set : str, default="default" - Name of the set of test parameters to return, for use in tests. If no - special parameters are defined for a value, will return `"default"` set. - There are no reserved values for parameter estimators. - - Returns - ------- - params : dict or list of dict, default = {} - Parameters to create testing instances of the class - Each dict are parameters to construct an "interesting" test instance, i.e., - `MyClass(**params)` or `MyClass(**params[i])` creates a valid test instance. - `create_test_instance` uses the first (or only) dictionary in `params` - """ - params = [ - {"param": "param", "func": lambda X: "foo"}, - {"param": "param", "func": lambda X, kwarg: "foo", "kw_args": {"kwarg": 1}}, - ] - return params From af00596c30e5e79ce9183fe9584b4a5959e1f505 Mon Sep 17 00:00:00 2001 From: Tomas Pereira de Vasconcelos Date: Sun, 17 Dec 2023 20:21:44 +0000 Subject: [PATCH 08/12] Document `kw_args` and `X_type` --- sktime/param_est/compose/_func_fitter.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sktime/param_est/compose/_func_fitter.py b/sktime/param_est/compose/_func_fitter.py index 8757d3e0718..c865b7e447f 100644 --- a/sktime/param_est/compose/_func_fitter.py +++ b/sktime/param_est/compose/_func_fitter.py @@ -26,6 +26,13 @@ class FunctionParamFitter(BaseParamFitter): The callable to use for the parameter estimation. This will be passed the same arguments as estimator, with args and kwargs forwarded. + kw_args : dict, default=None + Dictionary of additional keyword arguments to pass to func. + X_type : str, one of "pd.DataFrame, pd.Series, np.ndarray", or list thereof + default = ["pd.DataFrame", "pd.Series", "np.ndarray"] + list of types that func is assumed to allow for X (see signature above) + if X passed to transform/inverse_transform is not on the list, + it will be converted to the first list element before passed to funcs See Also -------- From 264d72401e982f531dbd00caafa688296f8c2c30 Mon Sep 17 00:00:00 2001 From: Tomas Pereira de Vasconcelos Date: Sun, 17 Dec 2023 20:56:00 +0000 Subject: [PATCH 09/12] Fix doctests --- sktime/param_est/compose/_func_fitter.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sktime/param_est/compose/_func_fitter.py b/sktime/param_est/compose/_func_fitter.py index c865b7e447f..b7d8310eb83 100644 --- a/sktime/param_est/compose/_func_fitter.py +++ b/sktime/param_est/compose/_func_fitter.py @@ -60,9 +60,11 @@ class FunctionParamFitter(BaseParamFitter): ... kw_args={"threshold": 7}, ... ) >>> param_est.fit(np.asarray([1, 2, 3, 4])) + FunctionParamFitter(...) >>> param_est.selected_forecaster_ 'naive-last' >>> param_est.fit(np.asarray([1, 2, 3, 4, 5, 6, 7])) + FunctionParamFitter(...) >>> param_est.selected_forecaster_ 'naive-seasonal' """ From 230cb44a1240dbb7808c9733d035c3023bfeb3fa Mon Sep 17 00:00:00 2001 From: Tomas Pereira de Vasconcelos Date: Sun, 17 Dec 2023 21:05:56 +0000 Subject: [PATCH 10/12] Improve examples in doctests --- sktime/param_est/compose/_func_fitter.py | 36 +++++++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/sktime/param_est/compose/_func_fitter.py b/sktime/param_est/compose/_func_fitter.py index b7d8310eb83..d156a92c02c 100644 --- a/sktime/param_est/compose/_func_fitter.py +++ b/sktime/param_est/compose/_func_fitter.py @@ -61,12 +61,40 @@ class FunctionParamFitter(BaseParamFitter): ... ) >>> param_est.fit(np.asarray([1, 2, 3, 4])) FunctionParamFitter(...) - >>> param_est.selected_forecaster_ - 'naive-last' + >>> param_est.get_fitted_params() + {'selected_forecaster': 'naive-last'} >>> param_est.fit(np.asarray([1, 2, 3, 4, 5, 6, 7])) FunctionParamFitter(...) - >>> param_est.selected_forecaster_ - 'naive-seasonal' + >>> param_est.get_fitted_params() + {'selected_forecaster': 'naive-seasonal'} + + The full conditional forecaster selection pipeline could look + like this: + + >>> from sktime.forecasting.compose import MultiplexForecaster + >>> from sktime.forecasting.naive import NaiveForecaster + >>> from sktime.param_est.plugin import PluginParamsForecaster + >>> forecaster = PluginParamsForecaster( + ... param_est=param_est, + ... forecaster=MultiplexForecaster( + ... forecasters=[ + ... ("naive-last", NaiveForecaster()), + ... ("naive-seasonal", NaiveForecaster(sp=7)), + ... ] + ... ), + ... ) + >>> forecaster.fit(np.asarray([1, 2, 3, 4])) + PluginParamsForecaster(...) + >>> forecaster.predict(fh=[1,2,3]) + array([[4.], + [4.], + [4.]]) + >>> forecaster.fit(np.asarray([1, 2, 3, 4, 5, 6, 7])) + PluginParamsForecaster(...) + >>> forecaster.predict(fh=[1,2,3]) + array([[1.], + [2.], + [3.]]) """ _tags = { From 0d8a86c8c2de2b6eb0691dd85c23930aaa648be1 Mon Sep 17 00:00:00 2001 From: Tomas Pereira de Vasconcelos Date: Sun, 17 Dec 2023 21:09:29 +0000 Subject: [PATCH 11/12] Add `FunctionParamFitter` to API docs --- docs/source/api_reference/param_est.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/source/api_reference/param_est.rst b/docs/source/api_reference/param_est.rst index 8369e2f6a7e..d8d22f42703 100644 --- a/docs/source/api_reference/param_est.rst +++ b/docs/source/api_reference/param_est.rst @@ -32,6 +32,12 @@ Composition ParamFitterPipeline +.. autosummary:: + :toctree: auto_generated/ + :template: class.rst + + FunctionParamFitter + .. currentmodule:: sktime.param_est.plugin .. autosummary:: From 855fb3f9ddd7982aa45332bf9bdc6d41225ae736 Mon Sep 17 00:00:00 2001 From: Tomas Pereira de Vasconcelos Date: Mon, 18 Dec 2023 00:05:41 +0000 Subject: [PATCH 12/12] Improve docs style --- sktime/param_est/compose/_func_fitter.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sktime/param_est/compose/_func_fitter.py b/sktime/param_est/compose/_func_fitter.py index d156a92c02c..c61e4dfe3c0 100644 --- a/sktime/param_est/compose/_func_fitter.py +++ b/sktime/param_est/compose/_func_fitter.py @@ -45,9 +45,10 @@ class FunctionParamFitter(BaseParamFitter): -------- This class could be used to contruct a parameter estimator that selects a forecaster based on the input data's length. The - selected forecaster can be stored in the `selected_forecaster_` + selected forecaster can be stored in the ``selected_forecaster_`` attribute, which can be then passed down to a - ``MultiplexForecaster`` via a ``PluginParamsForecaster``. + :class:`~sktime.forecasting.compose.MultiplexForecaster` via a + :class:`~sktime.param_est.plugin.PluginParamsForecaster`. >>> import numpy as np >>> param_est = FunctionParamFitter(