def __init__(
        self,
        name: str = "FittableDataTransformer",
        n_jobs: int = 1,
        verbose: bool = False,
        parallel_params: Union[bool, Sequence[str]] = False,
        mask_components: bool = True,
        global_fit: bool = False,
    ):
        """Base class for fittable transformers.

        All the deriving classes have to implement the static methods
        :func:`ts_transform()` and :func:`ts_fit()`. The fitting and transformation functions must
        be passed during the transformer's initialization. This class takes care of parallelizing
        operations involving multiple ``TimeSeries`` when possible.

        Parameters
        ----------
        name
            The data transformer's name
        n_jobs
            The number of jobs to run in parallel. Parallel jobs are created only when a `Sequence[TimeSeries]` is
            passed as input to a method, parallelising operations regarding different `TimeSeries`. Defaults to `1`
            (sequential). Setting the parameter to `-1` means using all the available processors.
            Note: for a small amount of data, the parallelisation overhead could end up increasing the total
            required amount of time.
        verbose
            Optionally, whether to print operations progress
        parallel_params
            Optionally, specifies which fixed parameters (i.e. the attributes initialized in the child-most
            class's `__init__`) take on different values for different parallel jobs. Fixed parameters specified
            by `parallel_params` are assumed to be a `Sequence` of values that should be used for that parameter
            in each parallel job; the length of this `Sequence` should equal the number of parallel jobs. If
            `parallel_params=True`, every fixed parameter will take on a different value for each
            parallel job. If `parallel_params=False`, every fixed parameter will take on the same value for
            each parallel job. If `parallel_params` is a `Sequence` of fixed attribute names, only those
            attribute names specified will take on different values between different parallel jobs.
        mask_components
            Optionally, whether to automatically apply any provided `component_mask`s to the
            `TimeSeries` inputs passed to `transform`, `fit`, `inverse_transform`, or `fit_transform`.
            If `True`, any specified `component_mask` will be applied to each input timeseries
            before passing them to the called method; the masked components will also be automatically
            'unmasked' in the returned `TimeSeries`. If `False`, then `component_mask` (if provided) will
            be passed as a keyword argument, but won't automatically be applied to the input timeseries.
            See `apply_component_mask` method of `BaseDataTransformer` for further details.
        global_fit
            Optionally, whether all `TimeSeries` passed to the `fit()` method should be used to fit
            a *single* set of parameters, or if a different set of parameters should be independently fitted
            to each provided `TimeSeries`. If `True`, then a `Sequence[TimeSeries]` is passed to `ts_fit`
            and a single set of parameters is fitted using all provided `TimeSeries`. If `False`, then
            each `TimeSeries` is individually passed to `ts_fit`, and a different set of fitted parameters
            if yielded for each of these fitting operations. See `ts_fit` for further details.

        Notes
        -----
        If `global_fit` is `False` and `fit` is called with a `Sequence` containing `n` different `TimeSeries`,
        then `n` sets of parameters will be fitted. When `transform` and/or `inverse_transform` is subsequently
        called with a `Series[TimeSeries]`, the `i`th set of fitted parameter values will be passed to
        `ts_transform`/`ts_inverse_transform` to transform the `i`th `TimeSeries` in this sequence. Conversely,
        if `global_fit` is `True`, then only a single set of fitted values will be produced when `fit` is
        provided with a `Sequence[TimeSeries]`. Consequently, if a `Sequence[TimeSeries]` is then passed to
        `transform`/`inverse_transform`, each of these `TimeSeries` will be transformed using the exact same set
        of fitted parameters.

        Note that if an invertible *and* fittable data transformer is to be globally fitted, the data transformer
        class should first inherit from `FittableDataTransformer` and then from `InvertibleDataTransformer`. In
        other words, `MyTransformer(FittableDataTransformer, InvertibleDataTransformer)` is correct, but
        `MyTransformer(InvertibleDataTransformer, FittableDataTransformer)` is **not**. If this is not implemented
        correctly, then the `global_fit` parameter will not be correctly passed to `FittableDataTransformer`'s
        constructor.

        The :func:`ts_transform()` and :func:`ts_fit()` methods are designed to be static methods instead of instance
        methods to allow an efficient parallelisation also when the scaler instance is storing a non-negligible
        amount of data. Using instance methods would imply copying the instance's data through multiple processes, which
        can easily introduce a bottleneck and nullify parallelisation benefits.

        Example
        --------
        >>> from darts.dataprocessing.transformers import FittableDataTransformer
        >>> from darts.utils.timeseries_generation import linear_timeseries
        >>>
        >>> class SimpleRangeScaler(FittableDataTransformer):
        >>>
        >>>     def __init__(self, scale, position):
        >>>         self._scale = scale
        >>>         self._position = position
        >>>         super().__init__()
        >>>
        >>>     @staticmethod
        >>>     def ts_transform(series, params):
        >>>         vals = series.all_values(copy=False)
        >>>         fit_params = params['fitted']
        >>>         unit_scale = (vals - fit_params['position'])/fit_params['scale']
        >>>         fix_params = params['fixed']
        >>>         rescaled = fix_params['_scale'] * unit_scale + fix_params['_position']
        >>>         return series.from_values(rescaled)
        >>>
        >>>     @staticmethod
        >>>     def ts_fit(series, params):
        >>>         vals = series.all_values(copy=False)
        >>>         scale = vals.max() - vals.min()
        >>>         position = vals[0]
        >>>         return {'scale': scale, 'position': position}
        >>>
        >>> series = linear_timeseries(length=5, start_value=1, end_value=5)
        >>> print(series)
        <TimeSeries (DataArray) (time: 5, component: 1, sample: 1)>
        array([[[1.]],

            [[2.]],

            [[3.]],

            [[4.]],

            [[5.]]])
        Coordinates:
        * time       (time) datetime64[ns] 2000-01-01 2000-01-02 ... 2000-01-05
        * component  (component) object 'linear'
        Dimensions without coordinates: sample
        Attributes:
            static_covariates:  None
            hierarchy:          None
        >>> series = SimpleRangeScaler(scale=2, position=-1).fit_transform(series)
        >>> print(series)
        <TimeSeries (DataArray) (time: 5, component: 1, sample: 1)>
        array([[[-1. ]],

            [[-0.5]],

            [[ 0. ]],

            [[ 0.5]],

            [[ 1. ]]])
        Coordinates:
        * time       (time) int64 0 1 2 3 4
        * component  (component) <U1 '0'
        Dimensions without coordinates: sample
        Attributes:
            static_covariates:  None
            hierarchy:          None
        """
        super().__init__(
            name=name,
            n_jobs=n_jobs,
            verbose=verbose,
            parallel_params=parallel_params,
            mask_components=mask_components,
        )

        self._fit_called = False
        self._fitted_params = None  # stores the fitted parameters/objects
        self._global_fit = global_fit
Base class for fittable transformers.

        All the deriving classes have to implement the static methods
        :func:`ts_transform()` and :func:`ts_fit()`. The fitting and transformation functions must
        be passed during the transformer's initialization. This class takes care of parallelizing
        operations involving multiple ``TimeSeries`` when possible.

        Parameters
        ----------
        name
            The data transformer's name
        n_jobs
            The number of jobs to run in parallel. Parallel jobs are created only when a `Sequence[TimeSeries]` is
            passed as input to a method, parallelising operations regarding different `TimeSeries`. Defaults to `1`
            (sequential). Setting the parameter to `-1` means using all the available processors.
            Note: for a small amount of data, the parallelisation overhead could end up increasing the total
            required amount of time.
        verbose
            Optionally, whether to print operations progress
        parallel_params
            Optionally, specifies which fixed parameters (i.e. the attributes initialized in the child-most
            class's `__init__`) take on different values for different parallel jobs. Fixed parameters specified
            by `parallel_params` are assumed to be a `Sequence` of values that should be used for that parameter
            in each parallel job; the length of this `Sequence` should equal the number of parallel jobs. If
            `parallel_params=True`, every fixed parameter will take on a different value for each
            parallel job. If `parallel_params=False`, every fixed parameter will take on the same value for
            each parallel job. If `parallel_params` is a `Sequence` of fixed attribute names, only those
            attribute names specified will take on different values between different parallel jobs.
        mask_components
            Optionally, whether to automatically apply any provided `component_mask`s to the
            `TimeSeries` inputs passed to `transform`, `fit`, `inverse_transform`, or `fit_transform`.
            If `True`, any specified `component_mask` will be applied to each input timeseries
            before passing them to the called method; the masked components will also be automatically
            'unmasked' in the returned `TimeSeries`. If `False`, then `component_mask` (if provided) will
            be passed as a keyword argument, but won't automatically be applied to the input timeseries.
            See `apply_component_mask` method of `BaseDataTransformer` for further details.
        global_fit
            Optionally, whether all `TimeSeries` passed to the `fit()` method should be used to fit
            a *single* set of parameters, or if a different set of parameters should be independently fitted
            to each provided `TimeSeries`. If `True`, then a `Sequence[TimeSeries]` is passed to `ts_fit`
            and a single set of parameters is fitted using all provided `TimeSeries`. If `False`, then
            each `TimeSeries` is individually passed to `ts_fit`, and a different set of fitted parameters
            if yielded for each of these fitting operations. See `ts_fit` for further details.

        Notes
        -----
        If `global_fit` is `False` and `fit` is called with a `Sequence` containing `n` different `TimeSeries`,
        then `n` sets of parameters will be fitted. When `transform` and/or `inverse_transform` is subsequently
        called with a `Series[TimeSeries]`, the `i`th set of fitted parameter values will be passed to
        `ts_transform`/`ts_inverse_transform` to transform the `i`th `TimeSeries` in this sequence. Conversely,
        if `global_fit` is `True`, then only a single set of fitted values will be produced when `fit` is
        provided with a `Sequence[TimeSeries]`. Consequently, if a `Sequence[TimeSeries]` is then passed to
        `transform`/`inverse_transform`, each of these `TimeSeries` will be transformed using the exact same set
        of fitted parameters.

        Note that if an invertible *and* fittable data transformer is to be globally fitted, the data transformer
        class should first inherit from `FittableDataTransformer` and then from `InvertibleDataTransformer`. In
        other words, `MyTransformer(FittableDataTransformer, InvertibleDataTransformer)` is correct, but
        `MyTransformer(InvertibleDataTransformer, FittableDataTransformer)` is **not**. If this is not implemented
        correctly, then the `global_fit` parameter will not be correctly passed to `FittableDataTransformer`'s
        constructor.

        The :func:`ts_transform()` and :func:`ts_fit()` methods are designed to be static methods instead of instance
        methods to allow an efficient parallelisation also when the scaler instance is storing a non-negligible
        amount of data. Using instance methods would imply copying the instance's data through multiple processes, which
        can easily introduce a bottleneck and nullify parallelisation benefits.

        Example
        --------
        >>> from darts.dataprocessing.transformers import FittableDataTransformer
        >>> from darts.utils.timeseries_generation import linear_timeseries
        >>>
        >>> class SimpleRangeScaler(FittableDataTransformer):
        >>>
        >>>     def __init__(self, scale, position):
        >>>         self._scale = scale
        >>>         self._position = position
        >>>         super().__init__()
        >>>
        >>>     @staticmethod
        >>>     def ts_transform(series, params):
        >>>         vals = series.all_values(copy=False)
        >>>         fit_params = params['fitted']
        >>>         unit_scale = (vals - fit_params['position'])/fit_params['scale']
        >>>         fix_params = params['fixed']
        >>>         rescaled = fix_params['_scale'] * unit_scale + fix_params['_position']
        >>>         return series.from_values(rescaled)
        >>>
        >>>     @staticmethod
        >>>     def ts_fit(series, params):
        >>>         vals = series.all_values(copy=False)
        >>>         scale = vals.max() - vals.min()
        >>>         position = vals[0]
        >>>         return {'scale': scale, 'position': position}
        >>>
        >>> series = linear_timeseries(length=5, start_value=1, end_value=5)
        >>> print(series)
        <TimeSeries (DataArray) (time: 5, component: 1, sample: 1)>
        array([[[1.]],

            [[2.]],

            [[3.]],

            [[4.]],

            [[5.]]])
        Coordinates:
        * time       (time) datetime64[ns] 2000-01-01 2000-01-02 ... 2000-01-05
        * component  (component) object 'linear'
        Dimensions without coordinates: sample
        Attributes:
            static_covariates:  None
            hierarchy:          None
        >>> series = SimpleRangeScaler(scale=2, position=-1).fit_transform(series)
        >>> print(series)
        <TimeSeries (DataArray) (time: 5, component: 1, sample: 1)>
        array([[[-1. ]],

            [[-0.5]],

            [[ 0. ]],

            [[ 0.5]],

            [[ 1. ]]])
        Coordinates:
        * time       (time) int64 0 1 2 3 4
        * component  (component) <U1 '0'
        Dimensions without coordinates: sample
        Attributes:
            static_covariates:  None
            hierarchy:          None
        
darts/dataprocessing/transformers/fittable_data_transformer.py