A universal scikit-learn style wrapper for statsmodels SARIMAX.
This class wraps the statsmodels.tsa.statespace.sarimax.SARIMAX model [1]_ [2]_
to follow the scikit-learn style. The following docstring is based on the
statsmodels documentation and it is highly recommended to visit their site
for the best level of detail.
The (p,d,q) order of the model for the number of AR parameters, differences,
and MA parameters.
d must be an integer indicating the integration order of the process.
p and q may either be an integers indicating the AR and MA orders
(so that all lags up to those orders are included) or else iterables
giving specific AR and / or MA lags to include.
The (P,D,Q,s) order of the seasonal component of the model for the AR
parameters, differences, MA parameters, and periodicity.
D must be an integer indicating the integration order of the process.
P and Q may either be an integers indicating the AR and MA orders
(so that all lags up to those orders are included) or else iterables
giving specific AR and / or MA lags to include.
s is an integer giving the periodicity (number of periods in season),
often it is 4 for quarterly data or 12 for monthly data.
Parameter controlling the deterministic trend polynomial A(t).
'c' indicates a constant (i.e. a degree zero component of the
trend polynomial).
't' indicates a linear trend with time.
'ct' indicates both, 'c' and 't'.
Can also be specified as an iterable defining the non-zero polynomial
exponents to include, in increasing order. For example, [1,1,0,1]
denotes a + b*t + ct^3.
Used when an explanatory variables, exog, are provided to select whether
or not coefficients on the exogenous estimators are allowed to vary over time.
Whether or not to use estimate the regression coefficients for the
exogenous variables as part of maximum likelihood estimation or through
the Kalman filter (i.e. recursive least squares). If
time_varying_regression is True, this must be set to False.
Whether or not to use partially conditional maximum likelihood
estimation.
If True, differencing is performed prior to estimation, which
discards the first s*D + d initial rows but results in a smaller
state-space formulation.
If False, the full SARIMAX model is put in state-space form so
that all data points can be used in estimation.
Whether or not to concentrate the scale (variance of the error term)
out of the likelihood. This reduces the number of parameters estimated
by maximum likelihood by one, but standard errors will then not
be available for the scale parameter.
The offset at which to start time trend values. Default is 1, so that
if trend='t' the trend is equal to 1, 2, ..., nobs. Typically is only
set when the model created by extending a previous dataset.
Whether or not to use exact diffuse initialization for non-stationary
states. Default is False (in which case approximate diffuse
initialization is used).
Additional keyword arguments to pass to the fit method of the
statsmodels SARIMAX model. The statsmodels SARIMAX.fit parameters
method, max_iter, start_params and disp have been moved to the
initialization of this model and will have priority over those provided
by the user using via sm_fit_kwargs.
Used when an explanatory variables, exog, are provided to select whether
or not coefficients on the exogenous estimators are allowed to vary over time.
Whether or not to use estimate the regression coefficients for the
exogenous variables as part of maximum likelihood estimation or through
the Kalman filter (i.e. recursive least squares). If
time_varying_regression is True, this must be set to False.
Whether or not to concentrate the scale (variance of the error term)
out of the likelihood. This reduces the number of parameters estimated
by maximum likelihood by one, but standard errors will then not
be available for the scale parameter.
Format of the object returned by the predict method. This is set
automatically according to the type of y used in the fit method to
train the model, 'numpy' or 'pandas'.
def__init__(self,order:tuple=(1,0,0),seasonal_order:tuple=(0,0,0,0),trend:str=None,measurement_error:bool=False,time_varying_regression:bool=False,mle_regression:bool=True,simple_differencing:bool=False,enforce_stationarity:bool=True,enforce_invertibility:bool=True,hamilton_representation:bool=False,concentrate_scale:bool=False,trend_offset:int=1,use_exact_diffuse:bool=False,dates=None,freq=None,missing='none',validate_specification:bool=True,method:str='lbfgs',maxiter:int=50,start_params:np.ndarray=None,disp:bool=False,sm_init_kwargs:dict[str,object]={},sm_fit_kwargs:dict[str,object]={},sm_predict_kwargs:dict[str,object]={})->None:self.order=orderself.seasonal_order=seasonal_orderself.trend=trendself.measurement_error=measurement_errorself.time_varying_regression=time_varying_regressionself.mle_regression=mle_regressionself.simple_differencing=simple_differencingself.enforce_stationarity=enforce_stationarityself.enforce_invertibility=enforce_invertibilityself.hamilton_representation=hamilton_representationself.concentrate_scale=concentrate_scaleself.trend_offset=trend_offsetself.use_exact_diffuse=use_exact_diffuseself.dates=datesself.freq=freqself.missing=missingself.validate_specification=validate_specificationself.method=methodself.maxiter=maxiterself.start_params=start_paramsself.disp=disp# Create the dictionaries with the additional statsmodels parameters to be # used during the init, fit and predict methods. Note that the statsmodels # SARIMAX.fit parameters `method`, `max_iter`, `start_params` and `disp` # have been moved to the initialization of this model and will have # priority over those provided by the user using via `sm_fit_kwargs`.self.sm_init_kwargs=sm_init_kwargsself.sm_fit_kwargs=sm_fit_kwargsself.sm_predict_kwargs=sm_predict_kwargs# Params that can be set with the `set_params` method_,_,_,_sarimax_params=inspect.getargvalues(inspect.currentframe())self._sarimax_params={k:vfork,vin_sarimax_params.items()ifknotin['self','_','_sarimax_params']}self._consolidate_kwargs()# Create Results Attributes self.output_type=Noneself.sarimax=Noneself.fitted=Falseself.sarimax_res=Noneself.training_index=None
Create the dictionaries to be used during the init, fit, and predict methods.
Note that the parameters in this model's initialization take precedence
over those provided by the user using via the statsmodels kwargs dicts.
def_consolidate_kwargs(self)->None:""" Create the dictionaries to be used during the init, fit, and predict methods. Note that the parameters in this model's initialization take precedence over those provided by the user using via the statsmodels kwargs dicts. Parameters ---------- self Returns ------- None """# statsmodels.tsa.statespace.SARIMAX parameters_init_kwargs=self.sm_init_kwargs.copy()_init_kwargs.update({'order':self.order,'seasonal_order':self.seasonal_order,'trend':self.trend,'measurement_error':self.measurement_error,'time_varying_regression':self.time_varying_regression,'mle_regression':self.mle_regression,'simple_differencing':self.simple_differencing,'enforce_stationarity':self.enforce_stationarity,'enforce_invertibility':self.enforce_invertibility,'hamilton_representation':self.hamilton_representation,'concentrate_scale':self.concentrate_scale,'trend_offset':self.trend_offset,'use_exact_diffuse':self.use_exact_diffuse,'dates':self.dates,'freq':self.freq,'missing':self.missing,'validate_specification':self.validate_specification})self._init_kwargs=_init_kwargs# statsmodels.tsa.statespace.SARIMAX.fit parameters_fit_kwargs=self.sm_fit_kwargs.copy()_fit_kwargs.update({'method':self.method,'maxiter':self.maxiter,'start_params':self.start_params,'disp':self.disp,})self._fit_kwargs=_fit_kwargs# statsmodels.tsa.statespace.SARIMAXResults.get_forecast parametersself._predict_kwargs=self.sm_predict_kwargs.copy()
A helper method to create a new statsmodel SARIMAX model.
Additional keyword arguments to pass to the statsmodels SARIMAX model
when it is initialized can be added with the init_kwargs argument
when initializing the model.
def_create_sarimax(self,endog:np.ndarray|pd.Series|pd.DataFrame,exog:np.ndarray|pd.Series|pd.DataFrame|None=None)->None:""" A helper method to create a new statsmodel SARIMAX model. Additional keyword arguments to pass to the statsmodels SARIMAX model when it is initialized can be added with the `init_kwargs` argument when initializing the model. Parameters ---------- endog : numpy ndarray, pandas Series, pandas DataFrame The endogenous variable. exog : numpy ndarray, pandas Series, pandas DataFrame, default None The exogenous variables. Returns ------- None """self.sarimax=SARIMAX(endog=endog,exog=exog,**self._init_kwargs)
Additional keyword arguments to pass to the fit method of the
statsmodels SARIMAX model can be added with the fit_kwargs argument
when initializing the model.
Parameters:
Name
Type
Description
Default
y
numpy ndarray, pandas Series, pandas DataFrame
Training time series.
required
exog
numpy ndarray, pandas Series, pandas DataFrame
Exogenous variable/s included as predictor/s. Must have the same
number of observations as y and their indexes must be aligned so
that y[i] is regressed on exog[i].
deffit(self,y:np.ndarray|pd.Series|pd.DataFrame,exog:np.ndarray|pd.Series|pd.DataFrame|None=None)->None:""" Fit the model to the data. Additional keyword arguments to pass to the `fit` method of the statsmodels SARIMAX model can be added with the `fit_kwargs` argument when initializing the model. Parameters ---------- y : numpy ndarray, pandas Series, pandas DataFrame Training time series. exog : numpy ndarray, pandas Series, pandas DataFrame, default None Exogenous variable/s included as predictor/s. Must have the same number of observations as `y` and their indexes must be aligned so that y[i] is regressed on exog[i]. Returns ------- None """# Reset values in case the model has already been fitted.self.output_type=Noneself.sarimax_res=Noneself.fitted=Falseself.training_index=Noneself.output_type='numpy'ifisinstance(y,np.ndarray)else'pandas'self._create_sarimax(endog=y,exog=exog)self.sarimax_res=self.sarimax.fit(**self._fit_kwargs)self.fitted=Trueifself.output_type=='pandas':self.training_index=y.index
Forecast future values and, if desired, their confidence intervals.
Generate predictions (forecasts) n steps in the future with confidence
intervals. Note that if exogenous variables were used in the model fit,
they will be expected for the predict procedure and will fail otherwise.
Additional keyword arguments to pass to the get_forecast method of the
statsmodels SARIMAX model can be added with the predict_kwargs argument
when initializing the model.
@_check_fitteddefpredict(self,steps:int,exog:np.ndarray|pd.Series|pd.DataFrame|None=None,return_conf_int:bool=False,alpha:float=0.05)->np.ndarray|pd.DataFrame:""" Forecast future values and, if desired, their confidence intervals. Generate predictions (forecasts) n steps in the future with confidence intervals. Note that if exogenous variables were used in the model fit, they will be expected for the predict procedure and will fail otherwise. Additional keyword arguments to pass to the `get_forecast` method of the statsmodels SARIMAX model can be added with the `predict_kwargs` argument when initializing the model. Parameters ---------- steps : int Number of steps to predict. exog : numpy ndarray, pandas Series, pandas DataFrame, default None Value of the exogenous variable/s for the next steps. The number of observations needed is the number of steps to predict. return_conf_int : bool, default False Whether to get the confidence intervals of the forecasts. alpha : float, default 0.05 The confidence intervals for the forecasts are (1 - alpha) %. Returns ------- predictions : numpy ndarray, pandas DataFrame Values predicted by the forecaster and their estimated interval. The output type is the same as the type of `y` used in the fit method. - pred: predictions. - lower_bound: lower bound of the interval. (if `return_conf_int`) - upper_bound: upper bound of the interval. (if `return_conf_int`) """# This is done because statsmodels doesn't allow `exog` length greater than# the number of stepsifexogisnotNoneandlen(exog)>steps:warnings.warn(f"When predicting using exogenous variables, the `exog` parameter "f"must have the same length as the number of predicted steps. Since "f"len(exog) > steps, only the first {steps} observations are used.")exog=exog[:steps]predictions=self.sarimax_res.get_forecast(steps=steps,exog=exog,**self._predict_kwargs)ifnotreturn_conf_int:predictions=predictions.predicted_meanifself.output_type=='pandas':predictions=predictions.rename("pred").to_frame()else:ifself.output_type=='numpy':predictions=np.column_stack([predictions.predicted_mean,predictions.conf_int(alpha=alpha)])else:predictions=pd.concat((predictions.predicted_mean,predictions.conf_int(alpha=alpha)),axis=1)predictions.columns=['pred','lower_bound','upper_bound']returnpredictions
Recreate the results object with new data appended to the original data.
Creates a new result object applied to a dataset that is created by
appending new data to the end of the model's original data [1]_. The new
results can then be used for analysis or forecasting.
Parameters:
Name
Type
Description
Default
y
numpy ndarray, pandas Series, pandas DataFrame
New observations from the modeled time-series process.
required
exog
numpy ndarray, pandas Series, pandas DataFrame
New observations of exogenous estimators, if applicable. Must have
the same number of observations as y and their indexes must be
aligned so that y[i] is regressed on exog[i].
Whether or not to copy the initialization from the current results
set to the new model.
False
**kwargs
Keyword arguments may be used to modify model specification arguments
when created the new model object.
{}
Returns:
Type
Description
None
Notes
The y and exog arguments to this method must be formatted in the same
way (e.g. Pandas Series versus Numpy array) as were the y and exog
arrays passed to the original model.
The y argument to this method should consist of new observations that
occurred directly after the last element of y. For any other kind of
dataset, see the apply method.
This method will apply filtering to all of the original data as well as
to the new data. To apply filtering only to the new data (which can be
much faster if the original dataset is large), see the extend method.
@_check_fitteddefappend(self,y:np.ndarray|pd.Series|pd.DataFrame,exog:np.ndarray|pd.Series|pd.DataFrame|None=None,refit:bool=False,copy_initialization:bool=False,**kwargs)->None:""" Recreate the results object with new data appended to the original data. Creates a new result object applied to a dataset that is created by appending new data to the end of the model's original data [1]_. The new results can then be used for analysis or forecasting. Parameters ---------- y : numpy ndarray, pandas Series, pandas DataFrame New observations from the modeled time-series process. exog : numpy ndarray, pandas Series, pandas DataFrame, default None New observations of exogenous estimators, if applicable. Must have the same number of observations as `y` and their indexes must be aligned so that y[i] is regressed on exog[i]. refit : bool, default False Whether to re-fit the parameters, based on the combined dataset. copy_initialization : bool, default False Whether or not to copy the initialization from the current results set to the new model. **kwargs Keyword arguments may be used to modify model specification arguments when created the new model object. Returns ------- None Notes ----- The `y` and `exog` arguments to this method must be formatted in the same way (e.g. Pandas Series versus Numpy array) as were the `y` and `exog` arrays passed to the original model. The `y` argument to this method should consist of new observations that occurred directly after the last element of `y`. For any other kind of dataset, see the apply method. This method will apply filtering to all of the original data as well as to the new data. To apply filtering only to the new data (which can be much faster if the original dataset is large), see the extend method. References ---------- .. [1] Statsmodels MLEResults append API Reference. https://www.statsmodels.org/stable/generated/statsmodels.tsa.statespace.mlemodel.MLEResults.append.html#statsmodels.tsa.statespace.mlemodel.MLEResults.append """fit_kwargs=self._fit_kwargsifrefitelseNoneself.sarimax_res=self.sarimax_res.append(endog=y,exog=exog,refit=refit,copy_initialization=copy_initialization,fit_kwargs=fit_kwargs,**kwargs)
Apply the fitted parameters to new data unrelated to the original data.
Creates a new result object using the current fitted parameters, applied
to a completely new dataset that is assumed to be unrelated to the model's
original data [1]_. The new results can then be used for analysis or forecasting.
Parameters:
Name
Type
Description
Default
y
numpy ndarray, pandas Series, pandas DataFrame
New observations from the modeled time-series process.
required
exog
numpy ndarray, pandas Series, pandas DataFrame
New observations of exogenous estimators, if applicable. Must have
the same number of observations as y and their indexes must be
aligned so that y[i] is regressed on exog[i].
Whether or not to copy the initialization from the current results
set to the new model.
False
**kwargs
Keyword arguments may be used to modify model specification arguments
when created the new model object.
{}
Returns:
Type
Description
None
Notes
The y argument to this method should consist of new observations that
are not necessarily related to the original model's y dataset. For
observations that continue that original dataset by follow directly after
its last element, see the append and extend methods.
@_check_fitteddefapply(self,y:np.ndarray|pd.Series|pd.DataFrame,exog:np.ndarray|pd.Series|pd.DataFrame|None=None,refit:bool=False,copy_initialization:bool=False,**kwargs)->None:""" Apply the fitted parameters to new data unrelated to the original data. Creates a new result object using the current fitted parameters, applied to a completely new dataset that is assumed to be unrelated to the model's original data [1]_. The new results can then be used for analysis or forecasting. Parameters ---------- y : numpy ndarray, pandas Series, pandas DataFrame New observations from the modeled time-series process. exog : numpy ndarray, pandas Series, pandas DataFrame, default None New observations of exogenous estimators, if applicable. Must have the same number of observations as `y` and their indexes must be aligned so that y[i] is regressed on exog[i]. refit : bool, default False Whether to re-fit the parameters, using the new dataset. copy_initialization : bool, default False Whether or not to copy the initialization from the current results set to the new model. **kwargs Keyword arguments may be used to modify model specification arguments when created the new model object. Returns ------- None Notes ----- The `y` argument to this method should consist of new observations that are not necessarily related to the original model's `y` dataset. For observations that continue that original dataset by follow directly after its last element, see the append and extend methods. References ---------- .. [1] Statsmodels MLEResults apply API Reference. https://www.statsmodels.org/stable/generated/statsmodels.tsa.statespace.mlemodel.MLEResults.apply.html#statsmodels.tsa.statespace.mlemodel.MLEResults.apply """fit_kwargs=self._fit_kwargsifrefitelseNoneself.sarimax_res=self.sarimax_res.apply(endog=y,exog=exog,refit=refit,copy_initialization=copy_initialization,fit_kwargs=fit_kwargs,**kwargs)
Recreate the results object for new data that extends the original data.
Creates a new result object applied to a new dataset that is assumed to
follow directly from the end of the model's original data [1]_. The new
results can then be used for analysis or forecasting.
Parameters:
Name
Type
Description
Default
y
numpy ndarray, pandas Series, pandas DataFrame
New observations from the modeled time-series process.
required
exog
numpy ndarray, pandas Series, pandas DataFrame
New observations of exogenous estimators, if applicable. Must have
the same number of observations as y and their indexes must be
aligned so that y[i] is regressed on exog[i].
None
**kwargs
Keyword arguments may be used to modify model specification arguments
when created the new model object.
{}
Returns:
Type
Description
None
Notes
The y argument to this method should consist of new observations that
occurred directly after the last element of the model's original y
array. For any other kind of dataset, see the apply method.
This method will apply filtering only to the new data provided by the y
argument, which can be much faster than re-filtering the entire dataset.
However, the returned results object will only have results for the new
data. To retrieve results for both the new data and the original data,
see the append method.
@_check_fitteddefextend(self,y:np.ndarray|pd.Series|pd.DataFrame,exog:np.ndarray|pd.Series|pd.DataFrame|None=None,**kwargs)->None:""" Recreate the results object for new data that extends the original data. Creates a new result object applied to a new dataset that is assumed to follow directly from the end of the model's original data [1]_. The new results can then be used for analysis or forecasting. Parameters ---------- y : numpy ndarray, pandas Series, pandas DataFrame New observations from the modeled time-series process. exog : numpy ndarray, pandas Series, pandas DataFrame, default None New observations of exogenous estimators, if applicable. Must have the same number of observations as `y` and their indexes must be aligned so that y[i] is regressed on exog[i]. **kwargs Keyword arguments may be used to modify model specification arguments when created the new model object. Returns ------- None Notes ----- The `y` argument to this method should consist of new observations that occurred directly after the last element of the model's original `y` array. For any other kind of dataset, see the apply method. This method will apply filtering only to the new data provided by the `y` argument, which can be much faster than re-filtering the entire dataset. However, the returned results object will only have results for the new data. To retrieve results for both the new data and the original data, see the append method. References ---------- .. [1] Statsmodels MLEResults extend API Reference. https://www.statsmodels.org/dev/generated/statsmodels.tsa.statespace.mlemodel.MLEResults.extend.html#statsmodels.tsa.statespace.mlemodel.MLEResults.extend """self.sarimax_res=self.sarimax_res.extend(endog=y,exog=exog,**kwargs)
defset_params(self,**params:dict[str,object])->None:""" Set new values to the parameters of the estimator. Parameters ---------- params : dict Parameters values. Returns ------- None """params={k:vfork,vinparams.items()ifkinself._sarimax_params}forkey,valueinparams.items():setattr(self,key,value)self._consolidate_kwargs()# Reset values in case the model has already been fitted.self.output_type=Noneself.sarimax_res=Noneself.fitted=Falseself.training_index=None
Get the parameters of the model. The order of variables is the trend
coefficients, the k_exog exogenous coefficients, the k_ar AR
coefficients, and finally the k_ma MA coefficients.
@_check_fitteddefparams(self)->np.ndarray|pd.Series:""" Get the parameters of the model. The order of variables is the trend coefficients, the `k_exog` exogenous coefficients, the `k_ar` AR coefficients, and finally the `k_ma` MA coefficients. Returns ------- params : numpy ndarray, pandas Series The parameters of the model. """returnself.sarimax_res.params
@_check_fitteddefsummary(self,alpha:float=0.05,start:int=None)->object:""" Get a summary of the SARIMAXResults object. Parameters ---------- alpha : float, default 0.05 The confidence intervals for the forecasts are (1 - alpha) %. start : int, default None Integer of the start observation. Returns ------- summary : Summary instance This holds the summary table and text, which can be printed or converted to various output formats. """returnself.sarimax_res.summary(alpha=alpha,start=start)
@_check_fitteddefget_info_criteria(self,criteria:str='aic',method:str='standard')->float:""" Get the selected information criteria. Check https://www.statsmodels.org/dev/generated/statsmodels.tsa.statespace.sarimax.SARIMAXResults.info_criteria.html to know more about statsmodels info_criteria method. Parameters ---------- criteria : str, default 'aic' The information criteria to compute. Valid options are {'aic', 'bic', 'hqic'}. method : str, default 'standard' The method for information criteria computation. Default is 'standard' method; 'lutkepohl' computes the information criteria as in Lütkepohl (2007). Returns ------- metric : float The value of the selected information criteria. """ifcriterianotin['aic','bic','hqic']:raiseValueError("Invalid value for `criteria`. Valid options are 'aic', 'bic', ""and 'hqic'.")ifmethodnotin['standard','lutkepohl']:raiseValueError("Invalid value for `method`. Valid options are 'standard' and ""'lutkepohl'.")metric=self.sarimax_res.info_criteria(criteria=criteria,method=method)returnmetric
Scikit-learn style wrapper for the ARAR time-series model.
This estimator treats a univariate sequence as "the feature".
Call fit(y) with a 1D array-like of observations in time order, then
produce out-of-sample forecasts via predict(steps) and prediction intervals
via predict_interval(steps, level=...). In-sample diagnostics are available
through fitted_, residuals_() and summary().
deffit(self,y:pd.Series|np.ndarray,exog:None=None)->"Arar":""" Fit the ARAR model to a univariate time series. Parameters ---------- y : array-like of shape (n_samples,) Time-ordered numeric sequence. exog : None Exogenous variables. Ignored, present for API compatibility. Returns ------- self : Arar Fitted estimator. """y=np.asarray(y,dtype=float).ravel()ify.ndim!=1:raiseValueError("`y` must be a 1D array-like sequence.")ify.size<2andnotself.safe:raiseValueError("Series too short to fit ARAR when safe=False.")self.model_=arar(y,max_ar_depth=self.max_ar_depth,max_lag=self.max_lag,safe=self.safe)(Y,best_phi,best_lag,sigma2,psi,sbar,max_ar_depth,max_lag)=self.model_self.y_=np.asarray(Y,dtype=float)self.coef_=np.asarray(best_phi,dtype=float)self.lags_=tuple(best_lag)self.sigma2_=float(sigma2)self.psi_=np.asarray(psi,dtype=float)self.sbar_=float(sbar)self.max_ar_depth=max_ar_depthself.max_lag=max_lagself.n_features_in_=1self.fitted_values_=fitted_arar(self.model_)["fitted"]self.residuals_in_=residuals_arar(self.model_)returnself
defpredict(self,steps:int,exog:None=None)->np.ndarray:""" Generate mean forecasts steps ahead. Parameters ---------- steps : int Forecast horizon (must be > 0) exog : None Exogenous variables. Ignored, present for API compatibility. Returns ------- mean : ndarray of shape (h,) Point forecasts for steps 1..h. """check_is_fitted(self,"model_")ifnotisinstance(steps,(int,np.integer))orsteps<=0:raiseValueError("`steps` must be a positive integer.")returnforecast(self.model_,h=steps)["mean"]
defpredict_interval(self,steps:int=1,level=(80,95),as_frame:bool=True,exog:None=None)->pd.DataFrame|dict:""" Forecast with symmetric normal-theory prediction intervals. Parameters ---------- steps : int, default=1 Forecast horizon. level : iterable of int, default=(80, 95) Confidence levels in percent. as_frame : bool, default=True If True, return a tidy DataFrame with columns: 'mean', 'lower_<L>', 'upper_<L>' for each level L. exog : None Exogenous variables. Ignored, present for API compatibility. Returns ------- DataFrame or dict If as_frame=True: DataFrame indexed by step (1..h). Else: the raw dict from `predict_arar`. """check_is_fitted(self,"model_")out=forecast(self.model_,h=steps,level=level)ifnotas_frame:returnoutidx=pd.RangeIndex(1,steps+1,name="step")df=pd.DataFrame({"mean":out["mean"]},index=idx)fori,Linenumerate(out["level"]):df[f"lower_{L}"]=out["lower"][:,i]df[f"upper_{L}"]=out["upper"][:,i]returndf