If True, save custom functions used in the forecaster (weight_func) as
.py files. Custom functions need to be available in the environment
where the forecaster is going to be loaded.
defsave_forecaster(forecaster:object,file_name:str,save_custom_functions:bool=True,verbose:bool=True,suppress_warnings:bool=False)->None:""" Save forecaster model using joblib. If custom functions are used to create weights, they are saved as .py files. Parameters ---------- forecaster : Forecaster Forecaster created with skforecast library. file_name : str File name given to the object. The save extension will be .joblib. save_custom_functions : bool, default True If True, save custom functions used in the forecaster (weight_func) as .py files. Custom functions need to be available in the environment where the forecaster is going to be loaded. verbose : bool, default True Print summary about the forecaster saved. suppress_warnings : bool, default False If `True`, skforecast warnings will be suppressed. See skforecast.exceptions.warn_skforecast_categories for more information. Returns ------- None """set_skforecast_warnings(suppress_warnings,action='ignore')file_name=Path(file_name).with_suffix('.joblib')# Save forecasterjoblib.dump(forecaster,filename=file_name)ifsave_custom_functions:# Save custom functions to create weightsifhasattr(forecaster,'weight_func')andforecaster.weight_funcisnotNone:ifisinstance(forecaster.weight_func,dict):forfuninset(forecaster.weight_func.values()):file_name=fun.__name__+'.py'withopen(file_name,'w')asfile:file.write(inspect.getsource(fun))else:file_name=forecaster.weight_func.__name__+'.py'withopen(file_name,'w')asfile:file.write(inspect.getsource(forecaster.weight_func))else:ifhasattr(forecaster,'weight_func')andforecaster.weight_funcisnotNone:warnings.warn("Custom function(s) used to create weights are not saved. To save them, ""set `save_custom_functions` to `True`.",SaveLoadSkforecastWarning)ifhasattr(forecaster,'window_features')andforecaster.window_featuresisnotNone:skforecast_classes={'RollingFeatures'}custom_classes=set(forecaster.window_features_class_names)-skforecast_classesifcustom_classes:warnings.warn("The Forecaster includes custom user-defined classes in the ""`window_features` argument. These classes are not saved automatically ""when saving the Forecaster. Please ensure you save these classes ""manually and import them before loading the Forecaster.\n"" Custom classes: "+', '.join(custom_classes)+"\n""Visit the documentation for more information: ""https://skforecast.org/latest/user_guides/save-load-forecaster.html#saving-and-loading-a-forecaster-model-with-custom-features",SaveLoadSkforecastWarning)ifverbose:forecaster.summary()set_skforecast_warnings(suppress_warnings,action='default')
Load forecaster model using joblib. If the forecaster was saved with
custom user-defined classes as as window features or custom
functions to create weights, these objects must be available
in the environment where the forecaster is going to be loaded.
defload_forecaster(file_name:str,verbose:bool=True,suppress_warnings:bool=False)->object:""" Load forecaster model using joblib. If the forecaster was saved with custom user-defined classes as as window features or custom functions to create weights, these objects must be available in the environment where the forecaster is going to be loaded. Parameters ---------- file_name: str Object file name. verbose: bool, default True Print summary about the forecaster loaded. suppress_warnings : bool, default False If `True`, skforecast warnings will be suppressed. See skforecast.exceptions.warn_skforecast_categories for more information. Returns ------- forecaster: Forecaster Forecaster created with skforecast library. """set_skforecast_warnings(suppress_warnings,action='ignore')forecaster=joblib.load(filename=Path(file_name))forecaster_v=forecaster.skforecast_versionifforecaster_v!=__version__:warnings.warn(f"The skforecast version installed in the environment differs "f"from the version used to create the forecaster.\n"f" Installed Version : {__version__}\n"f" Forecaster Version : {forecaster_v}\n"f"This may create incompatibilities when using the library.",SkforecastVersionWarning)ifverbose:forecaster.summary()set_skforecast_warnings(suppress_warnings,action='default')returnforecaster
definitialize_lags(forecaster_name:str,lags:Any)->tuple[np.ndarray[int]|None,list[str]|None,int|None]:""" Check lags argument input and generate the corresponding numpy ndarray. Parameters ---------- forecaster_name : str Forecaster name. lags : Any Lags used as predictors. Returns ------- lags : numpy ndarray, None Lags used as predictors. lags_names : list, None Names of the lags used as predictors. max_lag : int, None Maximum value of the lags. """lags_names=Nonemax_lag=NoneiflagsisnotNone:ifisinstance(lags,int):iflags<1:raiseValueError("Minimum value of lags allowed is 1.")lags=np.arange(1,lags+1)ifisinstance(lags,(list,tuple,range)):lags=np.array(lags)ifisinstance(lags,np.ndarray):iflags.size==0:returnNone,None,Noneiflags.ndim!=1:raiseValueError("`lags` must be a 1-dimensional array.")ifnotnp.issubdtype(lags.dtype,np.integer):raiseTypeError("All values in `lags` must be integers.")ifnp.any(lags<1):raiseValueError("Minimum value of lags allowed is 1.")else:ifforecaster_name=='ForecasterDirectMultiVariate':raiseTypeError(f"`lags` argument must be a dict, int, 1d numpy ndarray, range, "f"tuple or list. Got {type(lags)}.")else:raiseTypeError(f"`lags` argument must be an int, 1d numpy ndarray, range, "f"tuple or list. Got {type(lags)}.")lags=np.sort(lags)lags_names=[f'lag_{i}'foriinlags]max_lag=max(lags)returnlags,lags_names,max_lag
Check weights arguments, weight_func and series_weights for the different
forecasters. Create source_code_weight_func, source code of the custom
function(s) used to create weights.
definitialize_weights(forecaster_name:str,estimator:object,weight_func:Callable|dict[str,Callable],series_weights:dict[str,float])->tuple[Callable|dict[str,Callable]|None,str|dict[str,str]|None,dict[str,float]|None]:""" Check weights arguments, `weight_func` and `series_weights` for the different forecasters. Create `source_code_weight_func`, source code of the custom function(s) used to create weights. Parameters ---------- forecaster_name : str Forecaster name. estimator : estimator or pipeline compatible with the scikit-learn API Estimator of the forecaster. weight_func : Callable, dict Argument `weight_func` of the forecaster. series_weights : dict Argument `series_weights` of the forecaster. Returns ------- weight_func : Callable, dict Argument `weight_func` of the forecaster. source_code_weight_func : str, dict Argument `source_code_weight_func` of the forecaster. series_weights : dict Argument `series_weights` of the forecaster. Only ForecasterRecursiveMultiSeries. """source_code_weight_func=Noneifweight_funcisnotNone:ifforecaster_namein['ForecasterRecursiveMultiSeries']:ifnotisinstance(weight_func,(Callable,dict)):raiseTypeError(f"Argument `weight_func` must be a Callable or a dict of "f"Callables. Got {type(weight_func)}.")elifnotisinstance(weight_func,Callable):raiseTypeError(f"Argument `weight_func` must be a Callable. Got {type(weight_func)}.")ifisinstance(weight_func,dict):source_code_weight_func={}forkeyinweight_func:source_code_weight_func[key]=inspect.getsource(weight_func[key])else:source_code_weight_func=inspect.getsource(weight_func)if'sample_weight'notininspect.signature(estimator.fit).parameters:warnings.warn(f"Argument `weight_func` is ignored since estimator {estimator} "f"does not accept `sample_weight` in its `fit` method.",IgnoredArgumentWarning)weight_func=Nonesource_code_weight_func=Noneifseries_weightsisnotNone:ifnotisinstance(series_weights,dict):raiseTypeError(f"Argument `series_weights` must be a dict of floats or ints."f"Got {type(series_weights)}.")if'sample_weight'notininspect.signature(estimator.fit).parameters:warnings.warn(f"Argument `series_weights` is ignored since estimator {estimator} "f"does not accept `sample_weight` in its `fit` method.",IgnoredArgumentWarning)series_weights=Nonereturnweight_func,source_code_weight_func,series_weights
Initialize transformer_series_ attribute for the Forecasters Multiseries.
If transformer_series is None, no transformation is applied.
If transformer_series is a scikit-learn transformer (object), the same
transformer is applied to all series (series_names_in_).
If transformer_series is a dict, a different transformer can be
applied to each series. The keys of the dictionary must be the same as the
names of the series in series_names_in_.
An instance of a transformer (preprocessor) compatible with the scikit-learn
preprocessing API with methods: fit, transform, fit_transform and
inverse_transform.
definitialize_transformer_series(forecaster_name:str,series_names_in_:list[str],encoding:str|None=None,transformer_series:object|dict[str,object|None]|None=None)->dict[str,object|None]:""" Initialize `transformer_series_` attribute for the Forecasters Multiseries. - If `transformer_series` is `None`, no transformation is applied. - If `transformer_series` is a scikit-learn transformer (object), the same transformer is applied to all series (`series_names_in_`). - If `transformer_series` is a `dict`, a different transformer can be applied to each series. The keys of the dictionary must be the same as the names of the series in `series_names_in_`. Parameters ---------- forecaster_name : str Forecaster name. series_names_in_ : list Names of the series (levels) used during training. encoding : str, default None Encoding used to identify the different series (`ForecasterRecursiveMultiSeries`). transformer_series : object, dict, default None An instance of a transformer (preprocessor) compatible with the scikit-learn preprocessing API with methods: fit, transform, fit_transform and inverse_transform. Returns ------- transformer_series_ : dict Dictionary with the transformer for each series. It is created cloning the objects in `transformer_series` and is used internally to avoid overwriting. """ifforecaster_name=='ForecasterRecursiveMultiSeries':ifencodingisNone:series_names_in_=['_unknown_level']else:series_names_in_=series_names_in_+['_unknown_level']iftransformer_seriesisNone:transformer_series_={serie:Noneforserieinseries_names_in_}elifnotisinstance(transformer_series,dict):transformer_series_={serie:clone(transformer_series)forserieinseries_names_in_}else:transformer_series_={serie:Noneforserieinseries_names_in_}# Only elements already present in transformer_series_ are updatedtransformer_series_.update({k:deepcopy(v)fork,vintransformer_series.items()ifkintransformer_series_})series_not_in_transformer_series=(set(series_names_in_)-set(transformer_series.keys()))-{'_unknown_level'}ifseries_not_in_transformer_series:warnings.warn(f"{series_not_in_transformer_series} not present in `transformer_series`."f" No transformation is applied to these series.",IgnoredArgumentWarning)returntransformer_series_
defcheck_select_fit_kwargs(estimator:object,fit_kwargs:dict[str,object]|None=None)->dict[str,object]:""" Check if `fit_kwargs` is a dict and select only the keys that are used by the `fit` method of the estimator. Parameters ---------- estimator : object Estimator object. fit_kwargs : dict, default None Dictionary with the arguments to pass to the `fit' method of the forecaster. Returns ------- fit_kwargs : dict Dictionary with the arguments to be passed to the `fit` method of the estimator after removing the unused keys. """iffit_kwargsisNone:fit_kwargs={}else:ifnotisinstance(fit_kwargs,dict):raiseTypeError(f"Argument `fit_kwargs` must be a dict. Got {type(fit_kwargs)}.")fit_params=inspect.signature(estimator.fit).parameters# Non used keysnon_used_keys=[kforkinfit_kwargs.keys()ifknotinfit_params]ifnon_used_keys:warnings.warn(f"Argument/s {non_used_keys} ignored since they are not used by the "f"estimator's `fit` method.",IgnoredArgumentWarning)if'sample_weight'infit_kwargs.keys():warnings.warn("The `sample_weight` argument is ignored. Use `weight_func` to pass ""a function that defines the individual weights for each sample ""based on its index.",IgnoredArgumentWarning)delfit_kwargs['sample_weight']# Select only the keyword arguments allowed by the estimator's `fit` method.fit_kwargs={k:vfork,vinfit_kwargs.items()ifkinfit_params}returnfit_kwargs
defcheck_y(y:Any,series_id:str="`y`")->None:""" Raise Exception if `y` is not pandas Series or if it has missing values. Parameters ---------- y : Any Time series values. series_id : str, default '`y`' Identifier of the series used in the warning message. Returns ------- None """ifnotisinstance(y,pd.Series):raiseTypeError(f"{series_id} must be a pandas Series with a DatetimeIndex or a RangeIndex. "f"Found {type(y)}.")ify.isna().to_numpy().any():raiseValueError(f"{series_id} has missing values.")return
defcheck_exog(exog:pd.Series|pd.DataFrame,allow_nan:bool=True,series_id:str="`exog`")->None:""" Raise Exception if `exog` is not pandas Series or pandas DataFrame. If `allow_nan = True`, issue a warning if `exog` contains NaN values. Parameters ---------- exog : pandas Series, pandas DataFrame Exogenous variable/s included as predictor/s. allow_nan : bool, default True If True, allows the presence of NaN values in `exog`. If False (default), issue a warning if `exog` contains NaN values. series_id : str, default '`exog`' Identifier of the series for which the exogenous variable/s are used in the warning message. Returns ------- None """ifnotisinstance(exog,(pd.Series,pd.DataFrame)):raiseTypeError(f"{series_id} must be a pandas Series or DataFrame. Got {type(exog)}.")ifisinstance(exog,pd.Series)andexog.nameisNone:raiseValueError(f"When {series_id} is a pandas Series, it must have a name.")ifnotallow_nan:ifexog.isna().to_numpy().any():warnings.warn(f"{series_id} has missing values. Most machine learning models "f"do not allow missing values. Fitting the forecaster may fail.",MissingValuesWarning)return
defget_exog_dtypes(exog:pd.Series|pd.DataFrame,)->dict[str,type]:""" Store dtypes of `exog`. Parameters ---------- exog : pandas Series, pandas DataFrame Exogenous variable/s included as predictor/s. Returns ------- exog_dtypes : dict Dictionary with the dtypes in `exog`. """ifisinstance(exog,pd.Series):exog_dtypes={exog.name:exog.dtypes}else:exog_dtypes=exog.dtypes.to_dict()returnexog_dtypes
Raise Exception if exog has categorical columns with non integer values.
This is needed when using machine learning estimators that allow categorical
features.
Issue a Warning if exog has columns that are not init, float, or category.
defcheck_exog_dtypes(exog:pd.Series|pd.DataFrame,call_check_exog:bool=True,series_id:str="`exog`")->None:""" Raise Exception if `exog` has categorical columns with non integer values. This is needed when using machine learning estimators that allow categorical features. Issue a Warning if `exog` has columns that are not `init`, `float`, or `category`. Parameters ---------- exog : pandas Series, pandas DataFrame Exogenous variable/s included as predictor/s. call_check_exog : bool, default True If `True`, call `check_exog` function. series_id : str, default '`exog`' Identifier of the series for which the exogenous variable/s are used in the warning message. Returns ------- None """ifcall_check_exog:check_exog(exog=exog,allow_nan=False,series_id=series_id)valid_dtypes=("int","Int","float","Float","uint")ifisinstance(exog,pd.DataFrame):fordtype_nameinset(exog.dtypes.astype(str)):ifnot(dtype_name.startswith(valid_dtypes)ordtype_name=="category"):warnings.warn(f"{series_id} may contain only `int`, `float` or `category` dtypes. "f"Most machine learning models do not allow other types of values. "f"Fitting the forecaster may fail.",DataTypeWarning)breakforcolinexog.columns:ifisinstance(exog[col].dtype,pd.CategoricalDtype):ifnotnp.issubdtype(exog[col].cat.categories.dtype,np.integer):raiseTypeError("Categorical dtypes in exog must contain only integer values. ""See skforecast docs for more info about how to include ""categorical features https://skforecast.org/""latest/user_guides/categorical-features.html")else:dtype_name=str(exog.dtypes)ifnot(dtype_name.startswith(valid_dtypes)ordtype_name=="category"):warnings.warn(f"{series_id} may contain only `int`, `float` or `category` dtypes. Most "f"machine learning models do not allow other types of values. "f"Fitting the forecaster may fail.",DataTypeWarning)ifisinstance(exog.dtype,pd.CategoricalDtype):ifnotnp.issubdtype(exog.cat.categories.dtype,np.integer):raiseTypeError("Categorical dtypes in exog must contain only integer values. ""See skforecast docs for more info about how to include ""categorical features https://skforecast.org/""latest/user_guides/categorical-features.html")
Confidence of the prediction interval estimated. Sequence of percentiles
to compute, which must be between 0 and 100 inclusive. For example,
interval of 95% should be as interval = [2.5, 97.5].
Sequence of quantiles to compute, which must be between 0 and 1
inclusive. For example, quantiles of 0.05, 0.5 and 0.95 should be as
quantiles = [0.05, 0.5, 0.95].
defcheck_interval(interval:list[float]|tuple[float]|None=None,ensure_symmetric_intervals:bool=False,quantiles:list[float]|tuple[float]|None=None,alpha:float=None,alpha_literal:str|None='alpha')->None:""" Check provided confidence interval sequence is valid. Parameters ---------- interval : list, tuple, default None Confidence of the prediction interval estimated. Sequence of percentiles to compute, which must be between 0 and 100 inclusive. For example, interval of 95% should be as `interval = [2.5, 97.5]`. ensure_symmetric_intervals : bool, default False If True, ensure that the intervals are symmetric. quantiles : list, tuple, default None Sequence of quantiles to compute, which must be between 0 and 1 inclusive. For example, quantiles of 0.05, 0.5 and 0.95 should be as `quantiles = [0.05, 0.5, 0.95]`. alpha : float, default None The confidence intervals used in ForecasterStats are (1 - alpha) %. alpha_literal : str, default 'alpha' Literal used in the exception message when `alpha` is provided. Returns ------- None """ifintervalisnotNone:ifnotisinstance(interval,(list,tuple)):raiseTypeError("`interval` must be a `list` or `tuple`. For example, interval of 95% ""should be as `interval = [2.5, 97.5]`.")iflen(interval)!=2:raiseValueError("`interval` must contain exactly 2 values, respectively the ""lower and upper interval bounds. For example, interval of 95% ""should be as `interval = [2.5, 97.5]`.")if(interval[0]<0.)or(interval[0]>=100.):raiseValueError(f"Lower interval bound ({interval[0]}) must be >= 0 and < 100.")if(interval[1]<=0.)or(interval[1]>100.):raiseValueError(f"Upper interval bound ({interval[1]}) must be > 0 and <= 100.")ifinterval[0]>=interval[1]:raiseValueError(f"Lower interval bound ({interval[0]}) must be less than the "f"upper interval bound ({interval[1]}).")ifensure_symmetric_intervalsandinterval[0]+interval[1]!=100:raiseValueError(f"Interval must be symmetric, the sum of the lower, ({interval[0]}), "f"and upper, ({interval[1]}), interval bounds must be equal to "f"100. Got {interval[0]+interval[1]}.")ifquantilesisnotNone:ifnotisinstance(quantiles,(list,tuple)):raiseTypeError("`quantiles` must be a `list` or `tuple`. For example, quantiles ""0.05, 0.5, and 0.95 should be as `quantiles = [0.05, 0.5, 0.95]`.")forqinquantiles:if(q<0.)or(q>1.):raiseValueError("All elements in `quantiles` must be >= 0 and <= 1.")ifalphaisnotNone:ifnotisinstance(alpha,float):raiseTypeError(f"`{alpha_literal}` must be a `float`. For example, interval of 95% "f"should be as `alpha = 0.05`.")if(alpha<=0.)or(alpha>=1):raiseValueError(f"`{alpha_literal}` must have a value between 0 and 1. Got {alpha}.")
Check all inputs of predict method. This is a helper function to validate
that inputs used in predict method match attributes of a forecaster already
trained.
Confidence of the prediction interval estimated. Sequence of percentiles
to compute, which must be between 0 and 100 inclusive. For example,
interval of 95% should be as interval = [2.5, 97.5].
defcheck_predict_input(forecaster_name:str,steps:int|list[int],is_fitted:bool,exog_in_:bool,index_type_:type,index_freq_:str,window_size:int,last_window:pd.Series|pd.DataFrame|None,last_window_exog:pd.Series|pd.DataFrame|None=None,exog:pd.Series|pd.DataFrame|dict[str,pd.Series|pd.DataFrame]|None=None,exog_names_in_:list[str]|None=None,interval:list[float]|None=None,alpha:float|None=None,max_step:int|None=None,levels:str|list[str]|None=None,levels_forecaster:str|list[str]|None=None,series_names_in_:list[str]|None=None,encoding:str|None=None)->None:""" Check all inputs of predict method. This is a helper function to validate that inputs used in predict method match attributes of a forecaster already trained. Parameters ---------- forecaster_name : str Forecaster name. steps : int, list Number of future steps predicted. is_fitted: bool Tag to identify if the estimator has been fitted (trained). exog_in_ : bool If the forecaster has been trained using exogenous variable/s. index_type_ : type Type of index of the input used in training. index_freq_ : str Frequency of Index of the input used in training. window_size: int Size of the window needed to create the predictors. It is equal to `max_lag`. last_window : pandas Series, pandas DataFrame, None Values of the series used to create the predictors (lags) need in the first iteration of prediction (t + 1). last_window_exog : pandas Series, pandas DataFrame, default None Values of the exogenous variables aligned with `last_window` in ForecasterStats predictions. exog : pandas Series, pandas DataFrame, dict, default None Exogenous variable/s included as predictor/s. exog_names_in_ : list, default None Names of the exogenous variables used during training. interval : list, tuple, default None Confidence of the prediction interval estimated. Sequence of percentiles to compute, which must be between 0 and 100 inclusive. For example, interval of 95% should be as `interval = [2.5, 97.5]`. alpha : float, default None The confidence intervals used in ForecasterStats are (1 - alpha) %. max_step: int, default None Maximum number of steps allowed (`ForecasterDirect` and `ForecasterDirectMultiVariate`). levels : str, list, default None Time series to be predicted (`ForecasterRecursiveMultiSeries` and `ForecasterRnn). levels_forecaster : str, list, default None Time series used as output data of a multiseries problem in a RNN problem (`ForecasterRnn`). series_names_in_ : list, default None Names of the columns used during fit (`ForecasterRecursiveMultiSeries`, `ForecasterDirectMultiVariate` and `ForecasterRnn`). encoding : str, default None Encoding used to identify the different series (`ForecasterRecursiveMultiSeries`). Returns ------- None """ifnotis_fitted:raiseNotFittedError("This Forecaster instance is not fitted yet. Call `fit` with ""appropriate arguments before using predict.")ifisinstance(steps,(int,np.integer))andsteps<1:raiseValueError(f"`steps` must be an integer greater than or equal to 1. Got {steps}.")ifisinstance(steps,list)andmin(steps)<1:raiseValueError(f"The minimum value of `steps` must be equal to or greater than 1. "f"Got {min(steps)}.")ifmax_stepisnotNone:ifmax(steps)>max_step:raiseValueError(f"The maximum value of `steps` must be less than or equal to "f"the value of steps defined when initializing the forecaster. "f"Got {max(steps)}, but the maximum is {max_step}.")ifintervalisnotNoneoralphaisnotNone:check_interval(interval=interval,alpha=alpha)ifforecaster_namein['ForecasterRecursiveMultiSeries','ForecasterRnn']:ifnotisinstance(levels,(type(None),str,list)):raiseTypeError("`levels` must be a `list` of column names, a `str` of a ""column name or `None`.")levels_to_check=(levels_forecasterifforecaster_name=='ForecasterRnn'elseseries_names_in_)unknown_levels=set(levels)-set(levels_to_check)ifforecaster_name=='ForecasterRnn':iflen(unknown_levels)!=0:raiseValueError(f"`levels` names must be included in the series used during fit "f"({levels_to_check}). Got {levels}.")else:iflen(unknown_levels)!=0andlast_windowisnotNoneandencodingisnotNone:ifencoding=='onehot':warnings.warn(f"`levels` {unknown_levels} were not included in training. The resulting "f"one-hot encoded columns for this feature will be all zeros.",UnknownLevelWarning)else:warnings.warn(f"`levels` {unknown_levels} were not included in training. "f"Unknown levels are encoded as NaN, which may cause the "f"prediction to fail if the estimator does not accept NaN values.",UnknownLevelWarning)ifexogisNoneandexog_in_:raiseValueError("Forecaster trained with exogenous variable/s. ""Same variable/s must be provided when predicting.")ifexogisnotNoneandnotexog_in_:raiseValueError("Forecaster trained without exogenous variable/s. ""`exog` must be `None` when predicting.")# Checks last_window# Check last_window type (pd.Series or pd.DataFrame according to forecaster)ifisinstance(last_window,type(None))andforecaster_namenotin['ForecasterRecursiveMultiSeries','ForecasterRnn']:raiseValueError("`last_window` was not stored during training. If you don't want ""to retrain the Forecaster, provide `last_window` as argument.")ifforecaster_namein['ForecasterRecursiveMultiSeries','ForecasterDirectMultiVariate','ForecasterRnn']:ifnotisinstance(last_window,pd.DataFrame):raiseTypeError(f"`last_window` must be a pandas DataFrame. Got {type(last_window)}.")last_window_cols=last_window.columns.to_list()if(forecaster_namein["ForecasterRecursiveMultiSeries","ForecasterRnn"]andlen(set(levels)-set(last_window_cols))!=0):missing_levels=set(levels)-set(last_window_cols)raiseValueError(f"`last_window` must contain a column(s) named as the level(s) to be predicted. "f"The following `levels` are missing in `last_window`: {missing_levels}\n"f"Ensure that `last_window` contains all the necessary columns "f"corresponding to the `levels` being predicted.\n"f" Argument `levels` : {levels}\n"f" `last_window` columns : {last_window_cols}\n"f"Example: If `levels = ['series_1', 'series_2']`, make sure "f"`last_window` includes columns named 'series_1' and 'series_2'.")ifforecaster_name=='ForecasterDirectMultiVariate':iflen(set(series_names_in_)-set(last_window_cols))>0:raiseValueError(f"`last_window` columns must be the same as the `series` "f"column names used to create the X_train matrix.\n"f" `last_window` columns : {last_window_cols}\n"f" `series` columns X train : {series_names_in_}")else:ifnotisinstance(last_window,(pd.Series,pd.DataFrame)):raiseTypeError(f"`last_window` must be a pandas Series or DataFrame. "f"Got {type(last_window)}.")# Check last_window len, nulls and index (type and freq)iflen(last_window)<window_size:raiseValueError(f"`last_window` must have as many values as needed to "f"generate the predictors. For this forecaster it is {window_size}.")iflast_window.isna().to_numpy().any():warnings.warn("`last_window` has missing values. Most of machine learning models do ""not allow missing values. Prediction method may fail.",MissingValuesWarning)_,last_window_index=check_extract_values_and_index(data=last_window,data_label='`last_window`',ignore_freq=False,return_values=False)ifnotisinstance(last_window_index,index_type_):raiseTypeError(f"Expected index of type {index_type_} for `last_window`. "f"Got {type(last_window_index)}.")ifisinstance(last_window_index,pd.DatetimeIndex):ifnotlast_window_index.freq==index_freq_:raiseTypeError(f"Expected frequency of type {index_freq_} for `last_window`. "f"Got {last_window_index.freq}.")# Checks exogifexogisnotNone:# Check type, nulls and expected typeifforecaster_namein['ForecasterRecursiveMultiSeries']:ifnotisinstance(exog,(pd.Series,pd.DataFrame,dict)):raiseTypeError(f"`exog` must be a pandas Series, DataFrame or dict. Got {type(exog)}.")else:ifnotisinstance(exog,(pd.Series,pd.DataFrame)):raiseTypeError(f"`exog` must be a pandas Series or DataFrame. Got {type(exog)}.")ifisinstance(exog,dict):no_exog_levels=set(levels)-set(exog.keys())ifno_exog_levels:warnings.warn(f"`exog` does not contain keys for levels {no_exog_levels}. "f"Missing levels are filled with NaN. Most of machine learning "f"models do not allow missing values. Prediction method may fail.",MissingExogWarning)exogs_to_check=[(f"`exog` for series '{k}'",v)fork,vinexog.items()ifvisnotNoneandkinlevels]else:exogs_to_check=[('`exog`',exog)]last_step=max(steps)ifisinstance(steps,list)elsestepsexpected_index=expand_index(last_window_index,1)[0]forexog_name,exog_to_checkinexogs_to_check:ifnotisinstance(exog_to_check,(pd.Series,pd.DataFrame)):raiseTypeError(f"{exog_name} must be a pandas Series or DataFrame. Got {type(exog_to_check)}")ifexog_to_check.isna().to_numpy().any():warnings.warn(f"{exog_name} has missing values. Most of machine learning models "f"do not allow missing values. Prediction method may fail.",MissingValuesWarning)# Check exog has many values as distance to max step predictediflen(exog_to_check)<last_step:ifforecaster_namein['ForecasterRecursiveMultiSeries']:warnings.warn(f"{exog_name} doesn't have as many values as steps "f"predicted, {last_step}. Missing values are filled "f"with NaN. Most of machine learning models do not "f"allow missing values. Prediction method may fail.",MissingValuesWarning)else:raiseValueError(f"{exog_name} must have at least as many values as "f"steps predicted, {last_step}.")# Check name/columns are in exog_names_in_ifisinstance(exog_to_check,pd.DataFrame):col_missing=set(exog_names_in_).difference(set(exog_to_check.columns))ifcol_missing:ifforecaster_namein['ForecasterRecursiveMultiSeries']:warnings.warn(f"{col_missing} not present in {exog_name}. All "f"values will be NaN.",MissingExogWarning)else:raiseValueError(f"Missing columns in {exog_name}. Expected {exog_names_in_}. "f"Got {exog_to_check.columns.to_list()}.")else:ifexog_to_check.nameisNone:raiseValueError(f"When {exog_name} is a pandas Series, it must have a name. Got None.")ifexog_to_check.namenotinexog_names_in_:ifforecaster_namein['ForecasterRecursiveMultiSeries']:warnings.warn(f"'{exog_to_check.name}' was not observed during training. "f"{exog_name} is ignored. Exogenous variables must be one "f"of: {exog_names_in_}.",IgnoredArgumentWarning)else:raiseValueError(f"'{exog_to_check.name}' was not observed during training. "f"Exogenous variables must be: {exog_names_in_}.")# Check index dtype and freq_,exog_index=check_extract_values_and_index(data=exog_to_check,data_label=exog_name,ignore_freq=True,return_values=False)ifnotisinstance(exog_index,index_type_):raiseTypeError(f"Expected index of type {index_type_} for {exog_name}. "f"Got {type(exog_index)}.")# Check exog starts one step ahead of last_window end.ifexpected_index!=exog_index[0]:ifforecaster_namein['ForecasterRecursiveMultiSeries']:warnings.warn(f"To make predictions {exog_name} must start one step "f"ahead of `last_window`. Missing values are filled "f"with NaN.\n"f" `last_window` ends at : {last_window.index[-1]}.\n"f" {exog_name} starts at : {exog_index[0]}.\n"f" Expected index : {expected_index}.",MissingValuesWarning)else:raiseValueError(f"To make predictions {exog_name} must start one step "f"ahead of `last_window`.\n"f" `last_window` ends at : {last_window.index[-1]}.\n"f" {exog_name} starts at : {exog_index[0]}.\n"f" Expected index : {expected_index}.")# Checks ForecasterStatsifforecaster_name=='ForecasterStats':# Check last_window_exog type, len, nulls and index (type and freq)iflast_window_exogisnotNone:ifnotexog_in_:raiseValueError("Forecaster trained without exogenous variable/s. ""`last_window_exog` must be `None` when predicting.")ifnotisinstance(last_window_exog,(pd.Series,pd.DataFrame)):raiseTypeError(f"`last_window_exog` must be a pandas Series or a "f"pandas DataFrame. Got {type(last_window_exog)}.")iflen(last_window_exog)<window_size:raiseValueError(f"`last_window_exog` must have as many values as needed to "f"generate the predictors. For this forecaster it is {window_size}.")iflast_window_exog.isna().to_numpy().any():warnings.warn("`last_window_exog` has missing values. Most of machine learning ""models do not allow missing values. Prediction method may fail.",MissingValuesWarning)_,last_window_exog_index=check_extract_values_and_index(data=last_window_exog,data_label='`last_window_exog`',return_values=False)ifnotisinstance(last_window_exog_index,index_type_):raiseTypeError(f"Expected index of type {index_type_} for `last_window_exog`. "f"Got {type(last_window_exog_index)}.")ifisinstance(last_window_exog_index,pd.DatetimeIndex):ifnotlast_window_exog_index.freq==index_freq_:raiseTypeError(f"Expected frequency of type {index_freq_} for "f"`last_window_exog`. Got {last_window_exog_index.freq}.")# Check all columns are in the pd.DataFrame, last_window_exogifisinstance(last_window_exog,pd.DataFrame):col_missing=set(exog_names_in_).difference(set(last_window_exog.columns))ifcol_missing:raiseValueError(f"Missing columns in `last_window_exog`. Expected {exog_names_in_}. "f"Got {last_window_exog.columns.to_list()}.")else:iflast_window_exog.nameisNone:raiseValueError("When `last_window_exog` is a pandas Series, it must have a ""name. Got None.")iflast_window_exog.namenotinexog_names_in_:raiseValueError(f"'{last_window_exog.name}' was not observed during training. "f"Exogenous variables must be: {exog_names_in_}.")
defcheck_residuals_input(forecaster_name:str,use_in_sample_residuals:bool,in_sample_residuals_:np.ndarray|dict[str,np.ndarray]|None,out_sample_residuals_:np.ndarray|dict[str,np.ndarray]|None,use_binned_residuals:bool,in_sample_residuals_by_bin_:dict[str|int,np.ndarray|dict[int,np.ndarray]]|None,out_sample_residuals_by_bin_:dict[str|int,np.ndarray|dict[int,np.ndarray]]|None,levels:list[str]|None=None,encoding:str|None=None)->None:""" Check residuals input arguments in Forecasters. Parameters ---------- forecaster_name : str Forecaster name. use_in_sample_residuals : bool Indicates if in sample or out sample residuals are used. in_sample_residuals_ : numpy ndarray, dict Residuals of the model when predicting training data. out_sample_residuals_ : numpy ndarray, dict Residuals of the model when predicting non training data. use_binned_residuals : bool Indicates if residuals are binned. in_sample_residuals_by_bin_ : dict In sample residuals binned according to the predicted value each residual is associated with. out_sample_residuals_by_bin_ : dict Out of sample residuals binned according to the predicted value each residual is associated with. levels : list, default None Names of the series (levels) to be predicted (Forecasters multiseries). encoding : str, default None Encoding used to identify the different series (ForecasterRecursiveMultiSeries). Returns ------- None """forecasters_multiseries=['ForecasterRecursiveMultiSeries','ForecasterDirectMultiVariate','ForecasterRnn']ifuse_in_sample_residuals:ifuse_binned_residuals:residuals=in_sample_residuals_by_bin_literal="in_sample_residuals_by_bin_"else:residuals=in_sample_residuals_literal="in_sample_residuals_"if(residualsisNoneor(isinstance(residuals,dict)andnotresiduals)or(isinstance(residuals,np.ndarray)andresiduals.size==0)):raiseValueError(f"`forecaster.{literal}` is either None or empty. Use "f"`store_in_sample_residuals = True` when fitting the forecaster "f"or use the `set_in_sample_residuals()` method before predicting.")ifforecaster_nameinforecasters_multiseries:ifencodingisnotNone:unknown_levels=set(levels)-set(residuals.keys())ifunknown_levels:warnings.warn(f"`levels` {unknown_levels} are not present in `forecaster.{literal}`, "f"most likely because they were not present in the training data. "f"A random sample of the residuals from other levels will be used. "f"This can lead to inaccurate intervals for the unknown levels.",UnknownLevelWarning)else:ifuse_binned_residuals:residuals=out_sample_residuals_by_bin_literal="out_sample_residuals_by_bin_"else:residuals=out_sample_residuals_literal="out_sample_residuals_"if(residualsisNoneor(isinstance(residuals,dict)andnotresiduals)or(isinstance(residuals,np.ndarray)andresiduals.size==0)):raiseValueError(f"`forecaster.{literal}` is either None or empty. Use "f"`use_in_sample_residuals = True` or the "f"`set_out_sample_residuals()` method before predicting.")ifforecaster_nameinforecasters_multiseries:ifencodingisnotNone:unknown_levels=set(levels)-set(residuals.keys())ifunknown_levels:warnings.warn(f"`levels` {unknown_levels} are not present in `forecaster.{literal}`. "f"A random sample of the residuals from other levels will be used. "f"This can lead to inaccurate intervals for the unknown levels. "f"Otherwise, Use the `set_out_sample_residuals()` method before "f"predicting to set the residuals for these levels.",UnknownLevelWarning)ifforecaster_nameinforecasters_multiseries:forlevelinresiduals.keys():ifresiduals[level]isNoneorlen(residuals[level])==0:raiseValueError(f"Residuals for level '{level}' are None. Check `forecaster.{literal}`.")
Return values and index of series separately. Check that index is a pandas
DatetimeIndex or RangeIndex. Optionally, check that the index has a
frequency.
defcheck_extract_values_and_index(data:pd.Series|pd.DataFrame,data_label:str='`y`',ignore_freq:bool=False,return_values:bool=True)->tuple[np.ndarray|None,pd.Index]:""" Return values and index of series separately. Check that index is a pandas `DatetimeIndex` or `RangeIndex`. Optionally, check that the index has a frequency. Parameters ---------- data : pandas Series, pandas DataFrame Time series. data_label : str, default '`y`' Label of the data to be used in warnings and errors. ignore_freq : bool, default False If `True`, ignore the frequency of the index. If `False`, check that the index is a pandas `DatetimeIndex` with a frequency. return_values : bool, default True If `True` return the values of `data` as numpy ndarray. This option is intended to avoid copying data when it is not necessary. Returns ------- data_values : numpy ndarray, None Numpy array with values of `data`. data_index : pandas Index Index of `data`. """ifisinstance(data.index,pd.DatetimeIndex):ifnotignore_freqanddata.index.freqisNone:raiseValueError(f"{data_label} has a pandas DatetimeIndex without a frequency. "f"To avoid this error, set the frequency of the DatetimeIndex.")data_index=data.indexelifisinstance(data.index,pd.RangeIndex):data_index=data.indexelse:raiseTypeError(f"{data_label} has an unsupported index type. The index must be a "f"pandas DatetimeIndex or a RangeIndex. Got {type(data.index)}.")data_values=data.to_numpy(copy=True).ravel()ifreturn_valueselseNonereturndata_values,data_index
Cast exog to a specified types. This is done because, for a forecaster to
accept a categorical exog, it must contain only integer values. Due to the
internal modifications of numpy, the values may be casted to float, so
they have to be re-converted to int.
If exog is a pandas Series, exog_dtypes must be a dict with a
single value.
If exog_dtypes is category but the current type of exog is float,
then the type is cast to int and then to category.
defcast_exog_dtypes(exog:pd.Series|pd.DataFrame,exog_dtypes:dict[str,type],)->pd.Series|pd.DataFrame:# pragma: no cover""" Cast `exog` to a specified types. This is done because, for a forecaster to accept a categorical exog, it must contain only integer values. Due to the internal modifications of numpy, the values may be casted to `float`, so they have to be re-converted to `int`. - If `exog` is a pandas Series, `exog_dtypes` must be a dict with a single value. - If `exog_dtypes` is `category` but the current type of `exog` is `float`, then the type is cast to `int` and then to `category`. Parameters ---------- exog : pandas Series, pandas DataFrame Exogenous variables. exog_dtypes: dict Dictionary with name and type of the series or data frame columns. Returns ------- exog : pandas Series, pandas DataFrame Exogenous variables casted to the indicated dtypes. """# Remove keys from exog_dtypes not in exog.columnsexog_dtypes={k:vfork,vinexog_dtypes.items()ifkinexog.columns}ifisinstance(exog,pd.Series)andexog.dtypes!=list(exog_dtypes.values())[0]:exog=exog.astype(list(exog_dtypes.values())[0])elifisinstance(exog,pd.DataFrame):forcol,initial_dtypeinexog_dtypes.items():ifexog[col].dtypes!=initial_dtype:ifinitial_dtype=="category"andexog[col].dtypes==float:exog[col]=exog[col].astype(int).astype("category")else:exog[col]=exog[col].astype(initial_dtype)returnexog
defexog_to_direct(exog:pd.Series|pd.DataFrame,steps:int)->tuple[pd.DataFrame,list[str]]:""" Transforms `exog` to a pandas DataFrame with the shape needed for Direct forecasting. Parameters ---------- exog : pandas Series, pandas DataFrame Exogenous variables. steps : int Number of steps that will be predicted using exog. Returns ------- exog_direct : pandas DataFrame Exogenous variables transformed. exog_direct_names : list Names of the columns of the exogenous variables transformed. Only created if `exog` is a pandas Series or DataFrame. """ifnotisinstance(exog,(pd.Series,pd.DataFrame)):raiseTypeError(f"`exog` must be a pandas Series or DataFrame. Got {type(exog)}.")ifisinstance(exog,pd.Series):exog=exog.to_frame()n_rows=len(exog)exog_idx=exog.indexexog_cols=exog.columnsexog_direct=[]foriinrange(steps):exog_step=exog.iloc[i:n_rows-(steps-1-i),]exog_step.index=pd.RangeIndex(len(exog_step))exog_step.columns=[f"{col}_step_{i+1}"forcolinexog_cols]exog_direct.append(exog_step)iflen(exog_direct)>1:exog_direct=pd.concat(exog_direct,axis=1,copy=False)else:exog_direct=exog_direct[0]exog_direct_names=exog_direct.columns.to_list()exog_direct.index=exog_idx[-len(exog_direct):]returnexog_direct,exog_direct_names
defexog_to_direct_numpy(exog:np.ndarray|pd.Series|pd.DataFrame,steps:int)->tuple[np.ndarray,list[str]|None]:""" Transforms `exog` to numpy ndarray with the shape needed for Direct forecasting. Parameters ---------- exog : numpy ndarray, pandas Series, pandas DataFrame Exogenous variables, shape(samples,). If exog is a pandas format, the direct exog names are created. steps : int Number of steps that will be predicted using exog. Returns ------- exog_direct : numpy ndarray Exogenous variables transformed. exog_direct_names : list, None Names of the columns of the exogenous variables transformed. Only created if `exog` is a pandas Series or DataFrame. """ifisinstance(exog,(pd.Series,pd.DataFrame)):exog_cols=exog.columnsifisinstance(exog,pd.DataFrame)else[exog.name]exog_direct_names=[f"{col}_step_{i+1}"foriinrange(steps)forcolinexog_cols]exog=exog.to_numpy()else:exog_direct_names=Noneifnotisinstance(exog,np.ndarray):raiseTypeError(f"`exog` must be a numpy ndarray, pandas Series or DataFrame. "f"Got {type(exog)}.")ifexog.ndim==1:exog=np.expand_dims(exog,axis=1)n_rows=len(exog)exog_direct=[]foriinrange(steps):exog_step=exog[i:n_rows-(steps-1-i)]exog_direct.append(exog_step)iflen(exog_direct)>1:exog_direct=np.concatenate(exog_direct,axis=1)else:exog_direct=exog_direct[0]returnexog_direct,exog_direct_names
defexpand_index(index:pd.Index|None,steps:int)->pd.Index:""" Create a new index of length `steps` starting at the end of the index. Parameters ---------- index : pandas Index, None Original index. steps : int Number of steps to expand. Returns ------- new_index : pandas Index New index. """ifnotisinstance(steps,(int,np.integer)):raiseTypeError(f"`steps` must be an integer. Got {type(steps)}.")ifisinstance(index,pd.Index):ifisinstance(index,pd.DatetimeIndex):new_index=pd.date_range(start=index[-1]+index.freq,periods=steps,freq=index.freq)elifisinstance(index,pd.RangeIndex):new_index=pd.RangeIndex(start=index[-1]+1,stop=index[-1]+1+steps)else:raiseTypeError("Argument `index` must be a pandas DatetimeIndex or RangeIndex.")else:new_index=pd.RangeIndex(start=0,stop=steps)returnnew_index
Transform raw values of a numpy ndarray with a scikit-learn alike
transformer, preprocessor or ColumnTransformer. The transformer used must
have the following methods: fit, transform, fit_transform and
inverse_transform. ColumnTransformers are not allowed since they do not
have inverse_transform method.
Parameters:
Name
Type
Description
Default
array
numpy ndarray
Array to be transformed.
required
transformer
scikit-learn alike transformer, preprocessor, or ColumnTransformer.
Scikit-learn alike transformer (preprocessor) with methods: fit, transform,
fit_transform and inverse_transform.
deftransform_numpy(array:np.ndarray,transformer:object|None,fit:bool=False,inverse_transform:bool=False)->np.ndarray:""" Transform raw values of a numpy ndarray with a scikit-learn alike transformer, preprocessor or ColumnTransformer. The transformer used must have the following methods: fit, transform, fit_transform and inverse_transform. ColumnTransformers are not allowed since they do not have inverse_transform method. Parameters ---------- array : numpy ndarray Array to be transformed. transformer : scikit-learn alike transformer, preprocessor, or ColumnTransformer. Scikit-learn alike transformer (preprocessor) with methods: fit, transform, fit_transform and inverse_transform. fit : bool, default False Train the transformer before applying it. inverse_transform : bool, default False Transform back the data to the original representation. This is not available when using transformers of class scikit-learn ColumnTransformers. Returns ------- array_transformed : numpy ndarray Transformed array. """ifnotisinstance(array,np.ndarray):raiseTypeError(f"`array` argument must be a numpy ndarray. Got {type(array)}")iftransformerisNone:returnarrayarray_ndim=array.ndimifarray_ndim==1:array=array.reshape(-1,1)ifinverse_transformandisinstance(transformer,ColumnTransformer):raiseValueError("`inverse_transform` is not available when using ColumnTransformers.")withwarnings.catch_warnings():warnings.filterwarnings("ignore",message="X does not have valid feature names",category=UserWarning)ifnotinverse_transform:iffit:array_transformed=transformer.fit_transform(array)else:array_transformed=transformer.transform(array)else:array_transformed=transformer.inverse_transform(array)ifhasattr(array_transformed,'toarray'):# If the returned values are in sparse matrix format, it is converted to densearray_transformed=array_transformed.toarray()ifisinstance(array_transformed,(pd.Series,pd.DataFrame)):array_transformed=array_transformed.to_numpy()ifarray_ndim==1:array_transformed=array_transformed.ravel()returnarray_transformed
Transform raw values of pandas Series with a scikit-learn alike
transformer, preprocessor or ColumnTransformer. The transformer used must
have the following methods: fit, transform, fit_transform and
inverse_transform. ColumnTransformers are not allowed since they do not
have inverse_transform method.
Parameters:
Name
Type
Description
Default
series
pandas Series
Series to be transformed.
required
transformer
scikit-learn alike transformer, preprocessor, or ColumnTransformer.
Scikit-learn alike transformer (preprocessor) with methods: fit, transform,
fit_transform and inverse_transform.
deftransform_series(series:pd.Series,transformer:object|None,fit:bool=False,inverse_transform:bool=False)->pd.Series|pd.DataFrame:""" Transform raw values of pandas Series with a scikit-learn alike transformer, preprocessor or ColumnTransformer. The transformer used must have the following methods: fit, transform, fit_transform and inverse_transform. ColumnTransformers are not allowed since they do not have inverse_transform method. Parameters ---------- series : pandas Series Series to be transformed. transformer : scikit-learn alike transformer, preprocessor, or ColumnTransformer. Scikit-learn alike transformer (preprocessor) with methods: fit, transform, fit_transform and inverse_transform. fit : bool, default False Train the transformer before applying it. inverse_transform : bool, default False Transform back the data to the original representation. This is not available when using transformers of class scikit-learn ColumnTransformers. Returns ------- series_transformed : pandas Series, pandas DataFrame Transformed Series. Depending on the transformer used, the output may be a Series or a DataFrame. """ifnotisinstance(series,pd.Series):raiseTypeError(f"`series` argument must be a pandas Series. Got {type(series)}.")iftransformerisNone:returnseriesifseries.nameisNone:series.name='no_name'data=series.to_frame()iffitandhasattr(transformer,'fit'):transformer.fit(data)# If argument feature_names_in_ exits, is overwritten to allow using the # transformer on other series than those that were passed during fit.ifhasattr(transformer,'feature_names_in_')andtransformer.feature_names_in_[0]!=data.columns[0]:transformer=deepcopy(transformer)transformer.feature_names_in_=np.array([data.columns[0]],dtype=object)withwarnings.catch_warnings():warnings.simplefilter("ignore",category=UserWarning)ifinverse_transform:values_transformed=transformer.inverse_transform(data)else:values_transformed=transformer.transform(data)ifhasattr(values_transformed,'toarray'):# If the returned values are in sparse matrix format, it is converted to dense array.values_transformed=values_transformed.toarray()ifisinstance(values_transformed,np.ndarray)andvalues_transformed.shape[1]==1:series_transformed=pd.Series(data=values_transformed.ravel(),index=data.index,name=data.columns[0])elifisinstance(values_transformed,pd.DataFrame)andvalues_transformed.shape[1]==1:series_transformed=values_transformed.squeeze()else:series_transformed=pd.DataFrame(data=values_transformed,index=data.index,columns=transformer.get_feature_names_out())returnseries_transformed
Transform raw values of pandas DataFrame with a scikit-learn alike
transformer, preprocessor or ColumnTransformer. The transformer used must
have the following methods: fit, transform, fit_transform and
inverse_transform. ColumnTransformers are not allowed since they do not
have inverse_transform method.
Parameters:
Name
Type
Description
Default
df
pandas DataFrame
DataFrame to be transformed.
required
transformer
scikit-learn alike transformer, preprocessor, or ColumnTransformer.
Scikit-learn alike transformer (preprocessor) with methods: fit, transform,
fit_transform and inverse_transform.
deftransform_dataframe(df:pd.DataFrame,transformer:object|None,fit:bool=False,inverse_transform:bool=False)->pd.DataFrame:""" Transform raw values of pandas DataFrame with a scikit-learn alike transformer, preprocessor or ColumnTransformer. The transformer used must have the following methods: fit, transform, fit_transform and inverse_transform. ColumnTransformers are not allowed since they do not have inverse_transform method. Parameters ---------- df : pandas DataFrame DataFrame to be transformed. transformer : scikit-learn alike transformer, preprocessor, or ColumnTransformer. Scikit-learn alike transformer (preprocessor) with methods: fit, transform, fit_transform and inverse_transform. fit : bool, default False Train the transformer before applying it. inverse_transform : bool, default False Transform back the data to the original representation. This is not available when using transformers of class scikit-learn ColumnTransformers. Returns ------- df_transformed : pandas DataFrame Transformed DataFrame. """ifnotisinstance(df,pd.DataFrame):raiseTypeError(f"`df` argument must be a pandas DataFrame. Got {type(df)}")iftransformerisNone:returndfifinverse_transformandisinstance(transformer,ColumnTransformer):raiseValueError("`inverse_transform` is not available when using ColumnTransformers.")ifnotinverse_transform:iffit:values_transformed=transformer.fit_transform(df)else:values_transformed=transformer.transform(df)else:values_transformed=transformer.inverse_transform(df)ifhasattr(values_transformed,'toarray'):# If the returned values are in sparse matrix format, it is converted to densevalues_transformed=values_transformed.toarray()ifhasattr(transformer,'get_feature_names_out'):feature_names_out=transformer.get_feature_names_out()elifhasattr(transformer,'categories_'):feature_names_out=transformer.categories_else:feature_names_out=df.columnsdf_transformed=pd.DataFrame(data=values_transformed,index=df.index,columns=feature_names_out)returndf_transformed
defcheck_optional_dependency(package_name:str)->None:""" Check if an optional dependency is installed, if not raise an ImportError with installation instructions. Parameters ---------- package_name : str Name of the package to check. Returns ------- None """iffind_spec(package_name)isNone:try:extra,package_version=_find_optional_dependency(package_name=package_name)msg=(f"\n'{package_name}' is an optional dependency not included in the default "f"skforecast installation. Please run: `pip install \"{package_version}\"` to install it."f"\n\nAlternately, you can install it by running `pip install skforecast[{extra}]`")except:msg=f"\n'{package_name}' is needed but not installed. Please install it."raiseImportError(msg)
defmultivariate_time_series_corr(time_series:pd.Series,other:pd.DataFrame,lags:int|list[int]|np.ndarray[int],method:str='pearson')->pd.DataFrame:""" Compute correlation between a time_series and the lagged values of other time series. Parameters ---------- time_series : pandas Series Target time series. other : pandas DataFrame Time series whose lagged values are correlated to `time_series`. lags : int, list, numpy ndarray Lags to be included in the correlation analysis. method : str, default 'pearson' - 'pearson': standard correlation coefficient. - 'kendall': Kendall Tau correlation coefficient. - 'spearman': Spearman rank correlation. Returns ------- corr : pandas DataFrame Correlation values. """ifnotlen(time_series)==len(other):raiseValueError("`time_series` and `other` must have the same length.")ifnot(time_series.index==other.index).all():raiseValueError("`time_series` and `other` must have the same index.")ifisinstance(lags,int):lags=range(lags)corr={}forcolinother.columns:lag_values={}forlaginlags:lag_values[lag]=other[col].shift(lag)lag_values=pd.DataFrame(lag_values)lag_values.insert(0,None,time_series)corr[col]=lag_values.corr(method=method).iloc[1:,0]corr=pd.DataFrame(corr)corr.index=corr.index.astype('int64')corr.index.name="lag"returncorr
Select the optimal number of jobs to use in the fitting process. This
selection is based on heuristics and is not guaranteed to be optimal.
The number of jobs is chosen as follows:
If forecaster_name is 'ForecasterDirect' or 'ForecasterDirectMultiVariate'
and estimator_name is a linear estimator then n_jobs = 1,
otherwise n_jobs = cpu_count() - 1.
If estimator is a LGBMRegressor(n_jobs=1), then n_jobs = cpu_count() - 1.
If estimator is a LGBMRegressor with internal n_jobs != 1, then n_jobs = 1.
This is because lightgbm is highly optimized for gradient boosting and
parallelizes operations at a very fine-grained level, making additional
parallelization unnecessary and potentially harmful due to resource contention.
defselect_n_jobs_fit_forecaster(forecaster_name:str,estimator:object)->int:""" Select the optimal number of jobs to use in the fitting process. This selection is based on heuristics and is not guaranteed to be optimal. The number of jobs is chosen as follows: - If forecaster_name is 'ForecasterDirect' or 'ForecasterDirectMultiVariate' and estimator_name is a linear estimator then `n_jobs = 1`, otherwise `n_jobs = cpu_count() - 1`. - If estimator is a `LGBMRegressor(n_jobs=1)`, then `n_jobs = cpu_count() - 1`. - If estimator is a `LGBMRegressor` with internal n_jobs != 1, then `n_jobs = 1`. This is because `lightgbm` is highly optimized for gradient boosting and parallelizes operations at a very fine-grained level, making additional parallelization unnecessary and potentially harmful due to resource contention. Parameters ---------- forecaster_name : str Forecaster name. estimator : estimator or pipeline compatible with the scikit-learn API An instance of a estimator or pipeline compatible with the scikit-learn API. Returns ------- n_jobs : int The number of jobs to run in parallel. """ifisinstance(estimator,Pipeline):estimator=estimator[-1]estimator_name=type(estimator).__name__else:estimator_name=type(estimator).__name__linear_estimators=[estimator_nameforestimator_nameindir(sklearn.linear_model)ifnotestimator_name.startswith('_')]ifforecaster_namein['ForecasterDirect','ForecasterDirectMultiVariate']:ifestimator_nameinlinear_estimators:n_jobs=1elifestimator_name=='LGBMRegressor':n_jobs=joblib.cpu_count()-1ifestimator.n_jobs==1else1else:n_jobs=joblib.cpu_count()-1else:n_jobs=1returnn_jobs
Check and preprocess series argument in ForecasterRecursiveMultiSeries class.
If series is a wide-format pandas DataFrame, each column represents a
different time series, and the index must be either a DatetimeIndex or
a RangeIndex with frequency or step size, as appropriate
If series is a long-format pandas DataFrame with a MultiIndex, the
first level of the index must contain the series IDs, and the second
level must be a DatetimeIndex with the same frequency across all series.
If series is a dictionary, each key must be a series ID, and each value
must be a named pandas Series. All series must have the same index, which
must be either a DatetimeIndex or a RangeIndex, and they must share the
same frequency or step size, as appropriate.
When series is a pandas DataFrame, it is converted to a dictionary of pandas
Series, where the keys are the series IDs and the values are the Series with
the same index as the original DataFrame.
defcheck_preprocess_series(series:pd.DataFrame|dict[str,pd.Series|pd.DataFrame],)->tuple[dict[str,pd.Series],dict[str,pd.Index]]:""" Check and preprocess `series` argument in `ForecasterRecursiveMultiSeries` class. - If `series` is a wide-format pandas DataFrame, each column represents a different time series, and the index must be either a `DatetimeIndex` or a `RangeIndex` with frequency or step size, as appropriate - If `series` is a long-format pandas DataFrame with a MultiIndex, the first level of the index must contain the series IDs, and the second level must be a `DatetimeIndex` with the same frequency across all series. - If series is a dictionary, each key must be a series ID, and each value must be a named pandas Series. All series must have the same index, which must be either a `DatetimeIndex` or a `RangeIndex`, and they must share the same frequency or step size, as appropriate. When `series` is a pandas DataFrame, it is converted to a dictionary of pandas Series, where the keys are the series IDs and the values are the Series with the same index as the original DataFrame. Parameters ---------- series : pandas DataFrame, dict Training time series. Returns ------- series_dict : dict Dictionary with the series used during training. series_indexes : dict Dictionary with the index of each series. """ifnotisinstance(series,(pd.DataFrame,dict)):raiseTypeError(f"`series` must be a pandas DataFrame or a dict of DataFrames or Series. "f"Got {type(series)}.")ifisinstance(series,pd.DataFrame):ifnotisinstance(series.index,pd.MultiIndex):_,_=check_extract_values_and_index(data=series,data_label='`series`',return_values=False)series=series.copy()series.index.name=Noneseries_dict=series.to_dict(orient='series')else:ifnotisinstance(series.index.levels[1],pd.DatetimeIndex):raiseTypeError(f"The second level of the MultiIndex in `series` must be a "f"pandas DatetimeIndex with the same frequency for each series. "f"Found {type(series.index.levels[1])}.")first_col=series.columns[0]iflen(series.columns)!=1:warnings.warn(f"`series` DataFrame has multiple columns. Only the values of "f"first column, '{first_col}', will be used as series values. "f"All other columns will be ignored.",IgnoredArgumentWarning)series=series.copy()series.index=series.index.set_names([series.index.names[0],None])series_dict={series_id:series.loc[series_id][first_col].rename(series_id)forseries_idinseries.index.levels[0]}warnings.warn("Passing a DataFrame (either wide or long format) as `series` requires ""additional internal transformations, which can increase computational ""time. It is recommended to use a dictionary of pandas Series instead. ""For more details, see: ""https://skforecast.org/latest/user_guides/independent-multi-time-series-forecasting.html#input-data",InputTypeWarning)else:not_valid_series=[kfork,vinseries.items()ifnotisinstance(v,(pd.Series,pd.DataFrame))]ifnot_valid_series:raiseTypeError(f"If `series` is a dictionary, all series must be a named "f"pandas Series or a pandas DataFrame with a single column. "f"Review series: {not_valid_series}")series_dict={k:v.copy()fork,vinseries.items()}not_valid_index=[]indexes_freq=set()series_indexes={}fork,vinseries_dict.items():ifisinstance(v,pd.DataFrame):ifv.shape[1]!=1:raiseValueError(f"If `series` is a dictionary, all series must be a named "f"pandas Series or a pandas DataFrame with a single column. "f"Review series: '{k}'")series_dict[k]=v.iloc[:,0]series_dict[k].name=kidx=v.indexifisinstance(idx,pd.DatetimeIndex):indexes_freq.add(idx.freq)elifisinstance(idx,pd.RangeIndex):indexes_freq.add(idx.step)else:not_valid_index.append(k)ifv.isna().to_numpy().all():raiseValueError(f"All values of series '{k}' are NaN.")series_indexes[k]=idxifnot_valid_index:raiseTypeError(f"If `series` is a dictionary, all series must have a Pandas "f"RangeIndex or DatetimeIndex with the same step/frequency. "f"Review series: {not_valid_index}")ifNoneinindexes_freq:raiseValueError("If `series` is a dictionary, all series must have a Pandas ""RangeIndex or DatetimeIndex with the same step/frequency. ""If it a MultiIndex DataFrame, the second level must be a DatetimeIndex ""with the same frequency for each series. Found series with no ""frequency or step.")ifnotlen(indexes_freq)==1:raiseValueError(f"If `series` is a dictionary, all series must have a Pandas "f"RangeIndex or DatetimeIndex with the same step/frequency. "f"If it a MultiIndex DataFrame, the second level must be a DatetimeIndex "f"with the same frequency for each series. "f"Found frequencies: {sorted(indexes_freq)}")returnseries_dict,series_indexes
Check and preprocess exog argument in ForecasterRecursiveMultiSeries class.
If exog is a wide-format pandas DataFrame, it must share the same
index type as series. Each column represents a different exogenous variable,
and the same values are applied to all time series.
If exog is a long-format pandas Series or DataFrame with a MultiIndex,
the first level contains the series IDs to which it belongs, and the
second level contains a pandas DatetimeIndex. One column must be created
for each exogenous variable.
If exog is a dictionary, each key must be the series ID to which it
belongs, and each value must be a named pandas Series/DataFrame with
the same index type as series or None. While it is not necessary for
all values to include all the exogenous variables, the dtypes must be
consistent for the same exogenous variable across all series.
When exog is a pandas DataFrame, it is converted to a dictionary of pandas
DataFrames, where the keys are the series IDs and the values are the Series
with the same index as the original DataFrame.
defcheck_preprocess_exog_multiseries(series_names_in_:list[str],series_index_type:type,exog:pd.Series|pd.DataFrame|dict[str,pd.Series|pd.DataFrame|None],exog_dict:dict[str,pd.Series|pd.DataFrame|None],)->tuple[dict[str,pd.DataFrame|None],list[str]]:""" Check and preprocess `exog` argument in `ForecasterRecursiveMultiSeries` class. - If `exog` is a wide-format pandas DataFrame, it must share the same index type as series. Each column represents a different exogenous variable, and the same values are applied to all time series. - If `exog` is a long-format pandas Series or DataFrame with a MultiIndex, the first level contains the series IDs to which it belongs, and the second level contains a pandas DatetimeIndex. One column must be created for each exogenous variable. - If `exog` is a dictionary, each key must be the series ID to which it belongs, and each value must be a named pandas Series/DataFrame with the same index type as `series` or None. While it is not necessary for all values to include all the exogenous variables, the dtypes must be consistent for the same exogenous variable across all series. When `exog` is a pandas DataFrame, it is converted to a dictionary of pandas DataFrames, where the keys are the series IDs and the values are the Series with the same index as the original DataFrame. Parameters ---------- series_names_in_ : list Names of the series (levels) used during training. series_index_type : type Index type of the series used during training. exog : pandas Series, pandas DataFrame, dict Exogenous variable/s used during training. exog_dict : dict Dictionary with the exogenous variable/s used during training. Returns ------- exog_dict : dict Dictionary with the exogenous variable/s used during training. exog_names_in_ : list Names of the exogenous variables used during training. """ifnotisinstance(exog,(pd.Series,pd.DataFrame,dict)):raiseTypeError(f"`exog` must be a pandas Series, DataFrame, dictionary of pandas "f"Series/DataFrames or None. Got {type(exog)}.")ifisinstance(exog,(pd.Series,pd.DataFrame)):exog=exog.copy().to_frame()ifisinstance(exog,pd.Series)elseexog.copy()ifisinstance(exog.index,pd.MultiIndex):ifnotisinstance(exog.index.levels[1],pd.DatetimeIndex):raiseTypeError(f"When input data are pandas MultiIndex DataFrame, "f"`series` and `exog` second level index must be a "f"pandas DatetimeIndex. Found `exog` index type: "f"{type(exog.index.levels[1])}.")exog.index=exog.index.set_names([exog.index.names[0],None])exog_dict.update({series_id:exog.loc[series_id]forseries_idinexog.index.levels[0]ifseries_idinseries_names_in_})series_ids_in_exog=exog.index.levels[0]warnings.warn("Using a long-format DataFrame as `exog` requires additional transformations, ""which can increase computational time. It is recommended to use a dictionary of ""Series or DataFrames instead. For more information, see: ""https://skforecast.org/latest/user_guides/independent-multi-time-series-forecasting#input-data",InputTypeWarning)else:ifnotisinstance(exog.index,series_index_type):raiseTypeError(f"`exog` must have the same index type as `series`, pandas "f"RangeIndex or pandas DatetimeIndex.\n"f" `series` index type : {series_index_type}.\n"f" `exog` index type : {type(exog.index)}.")exog_dict={series_id:exogforseries_idinseries_names_in_}series_ids_in_exog=series_names_in_else:not_valid_exog=[kfork,vinexog.items()ifnotisinstance(v,(pd.Series,pd.DataFrame,type(None)))]ifnot_valid_exog:raiseTypeError(f"If `exog` is a dictionary, all exog must be a named pandas "f"Series, a pandas DataFrame or None. Review exog: {not_valid_exog}")# NOTE: Only elements already present in exog_dict are updated. Copy is# needed to avoid modifying the original exog.exog_dict.update({k:v.copy()fork,vinexog.items()ifkinseries_names_in_andvisnotNone})series_ids_in_exog=exog.keys()series_not_in_exog=set(series_names_in_)-set(series_ids_in_exog)ifseries_not_in_exog:warnings.warn(f"No `exog` for series {series_not_in_exog}. All values "f"of the exogenous variables for these series will be NaN.",MissingExogWarning)fork,vinexog_dict.items():ifvisnotNone:check_exog(exog=v,allow_nan=True)ifisinstance(v,pd.Series):v=v.to_frame()exog_dict[k]=vnot_valid_index=[kfork,vinexog_dict.items()ifvisnotNoneandnotisinstance(v.index,series_index_type)]ifnot_valid_index:raiseTypeError(f"All exog must have the same index type as `series`, which can be "f"either a pandas RangeIndex or a pandas DatetimeIndex. If either "f"`series` or `exog` is a pandas DataFrame with a MultiIndex, then "f"both must be pandas DatetimeIndex. Review exog for series: {not_valid_index}.")ifisinstance(exog,dict):# NOTE: Check that all exog have the same dtypes for common columnsexog_dtypes_buffer=pd.DataFrame({k:df.dtypesfork,dfinexog_dict.items()ifdfisnotNone})exog_dtypes_nunique=exog_dtypes_buffer.nunique(axis=1)ifnot(exog_dtypes_nunique==1).all():non_unique_dtypes_exogs=exog_dtypes_nunique[exog_dtypes_nunique!=1].index.to_list()raiseTypeError(f"Exog/s: {non_unique_dtypes_exogs} have different dtypes in different "f"series. If any of these variables are categorical, note that this "f"error can also occur when their internal categories "f"(`series.cat.categories`) differ between series. Please ensure "f"that all series have the same categories (and category order) "f"for each categorical variable.")exog_names_in_=list(set(columnfordfinexog_dict.values()ifdfisnotNoneforcolumnindf.columns.to_list()))else:exog_names_in_=list(exog.columns)ifisinstance(exog,pd.DataFrame)else[exog.name]iflen(set(exog_names_in_)-set(series_names_in_))!=len(exog_names_in_):raiseValueError(f"`exog` cannot contain a column named the same as one of the series.\n"f" `series` columns : {series_names_in_}.\n"f" `exog` columns : {exog_names_in_}.")returnexog_dict,exog_names_in_
Align series and exog according to their index. If needed, reindexing is
applied. Heading and trailing NaNs are removed from all series in
series_dict.
defalign_series_and_exog_multiseries(series_dict:dict[str,pd.Series],exog_dict:dict[str,pd.DataFrame]|None=None)->tuple[dict[str,pd.Series],dict[str,pd.DataFrame|None]]:""" Align series and exog according to their index. If needed, reindexing is applied. Heading and trailing NaNs are removed from all series in `series_dict`. Parameters ---------- series_dict : dict Dictionary with the series used during training. exog_dict : dict, default None Dictionary with the exogenous variable/s used during training. Returns ------- series_dict : dict Dictionary with the series used during training. exog_dict : dict Dictionary with the exogenous variable/s used during training. """forkinseries_dict.keys():ifnp.isnan(series_dict[k].iat[0])ornp.isnan(series_dict[k].iat[-1]):first_valid_index=series_dict[k].first_valid_index()last_valid_index=series_dict[k].last_valid_index()series_dict[k]=series_dict[k].loc[first_valid_index:last_valid_index]else:first_valid_index=series_dict[k].index[0]last_valid_index=series_dict[k].index[-1]ifexog_dict[k]isnotNone:ifnotseries_dict[k].index.equals(exog_dict[k].index):exog_dict[k]=exog_dict[k].loc[first_valid_index:last_valid_index]ifexog_dict[k].empty:warnings.warn(f"`exog` for series '{k}' is empty after aligning "f"with the series index. Exog values will be NaN.",MissingValuesWarning)exog_dict[k]=Noneeliflen(exog_dict[k])!=len(series_dict[k]):warnings.warn(f"`exog` for series '{k}' doesn't have values for "f"all the dates in the series. Missing values will be "f"filled with NaN.",MissingValuesWarning)exog_dict[k]=exog_dict[k].reindex(series_dict[k].index,fill_value=np.nan)returnseries_dict,exog_dict
defprepare_levels_multiseries(X_train_series_names_in_:list[str],levels:str|list[str]|None=None)->tuple[list[str],bool]:""" Prepare list of levels to be predicted in multiseries Forecasters. Parameters ---------- X_train_series_names_in_ : list Names of the series (levels) included in the matrix `X_train`. levels : str, list, default None Names of the series (levels) to be predicted. Returns ------- levels : list Names of the series (levels) to be predicted. input_levels_is_list : bool Indicates if input levels argument is a list. """input_levels_is_list=FalseiflevelsisNone:levels=X_train_series_names_in_elifisinstance(levels,str):levels=[levels]else:input_levels_is_list=Truereturnlevels,input_levels_is_list
Preprocess levels and last_window (when using self.last_window_) arguments
in multiseries Forecasters when predicting. Only levels whose last window
ends at the same datetime index will be predicted together.
defpreprocess_levels_self_last_window_multiseries(levels:list[str],input_levels_is_list:bool,last_window_:dict[str,pd.Series],)->tuple[list[str],pd.DataFrame]:""" Preprocess `levels` and `last_window` (when using self.last_window_) arguments in multiseries Forecasters when predicting. Only levels whose last window ends at the same datetime index will be predicted together. Parameters ---------- levels : list Names of the series (levels) to be predicted. input_levels_is_list : bool Indicates if input levels argument is a list. last_window_ : dict Dictionary with the last window of each series (self.last_window_). Returns ------- levels : list Names of the series (levels) to be predicted. last_window : pandas DataFrame Series values used to create the predictors (lags) needed in the first iteration of the prediction (t + 1). """available_last_windows=set()iflast_window_isNoneelseset(last_window_.keys())not_available_last_window=set(levels)-available_last_windowsifnot_available_last_window:levels=[levelforlevelinlevelsiflevelnotinnot_available_last_window]ifnotlevels:raiseValueError(f"No series to predict. None of the series {not_available_last_window} "f"are present in `last_window_` attribute. Provide `last_window` "f"as argument in predict method.")else:warnings.warn(f"Levels {not_available_last_window} are excluded from "f"prediction since they were not stored in `last_window_` "f"attribute during training. If you don't want to retrain "f"the Forecaster, provide `last_window` as argument.",IgnoredArgumentWarning)last_index_levels=[v.index[-1]fork,vinlast_window_.items()ifkinlevels]iflen(set(last_index_levels))>1:max_index_levels=max(last_index_levels)selected_levels=[kfork,vinlast_window_.items()ifkinlevelsandv.index[-1]==max_index_levels]series_excluded_from_last_window=set(levels)-set(selected_levels)levels=selected_levelsifinput_levels_is_listandseries_excluded_from_last_window:warnings.warn(f"Only series whose last window ends at the same index "f"can be predicted together. Series that do not reach "f"the maximum index, '{max_index_levels}', are excluded "f"from prediction: {series_excluded_from_last_window}.",IgnoredArgumentWarning)last_window=pd.DataFrame({k:vfork,vinlast_window_.items()ifkinlevels})returnlevels,last_window
defprepare_steps_direct(max_step:int|list[int]|np.ndarray[int],steps:int|list[int]|None=None)->list[int]:""" Prepare list of steps to be predicted in Direct Forecasters. Parameters ---------- max_step : int, list, numpy ndarray Maximum number of future steps the forecaster will predict when using predict methods. steps : int, list, None, default None Predict n steps. The value of `steps` must be less than or equal to the value of steps defined when initializing the forecaster. Starts at 1. - If `int`: Only steps within the range of 1 to int are predicted. - If `list`: List of ints. Only the steps contained in the list are predicted. - If `None`: As many steps are predicted as were defined at initialization. Returns ------- steps : list Steps to be predicted. """ifisinstance(steps,int):steps=list(np.arange(steps)+1)elifstepsisNone:ifisinstance(max_step,int):steps=list(np.arange(max_step)+1)else:steps=list(np.array(max_step))elifisinstance(steps,list):steps=list(np.array(steps))forstepinsteps:ifnotisinstance(step,(int,np.int64,np.int32)):raiseTypeError(f"`steps` argument must be an int, a list of ints or `None`. "f"Got {type(steps)}.")# Required since numpy 2.0steps=[int(step)forstepinstepsifstepisnotNone]returnsteps
If True, skforecast warnings will be suppressed. If False, skforecast
warnings will be shown as default. See
skforecast.exceptions.warn_skforecast_categories for more information.
defset_skforecast_warnings(suppress_warnings:bool,action:str='default')->None:""" Set skforecast warnings action. Parameters ---------- suppress_warnings : bool If `True`, skforecast warnings will be suppressed. If `False`, skforecast warnings will be shown as default. See skforecast.exceptions.warn_skforecast_categories for more information. action : str, default `'default'` Action to be taken when a warning is raised. See the warnings module for more information. Returns ------- None """ifsuppress_warnings:forcategoryinwarn_skforecast_categories:warnings.filterwarnings(action,category=category)