Plotting
Plotting¶
Plot forecasting residuals¶
Analyzing the residuals (errors) of predictions is useful to understand the behavior of a forecaster. The function skforecast.plot.plot_residuals
creates 3 plots:
A time-ordered plot of residual values
A distribution plot that showcases the distribution of residuals
A plot showcasing the autocorrelation of residuals
By examining the residual values over time, you can determine whether there is a pattern in the errors made by the forecast model. The distribution plot helps you understand whether the residuals are normally distributed, and the autocorrelation plot helps you identify whether there are any dependencies or relationships between the residuals.
# Libraries
# ==============================================================================
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.linear_model import Ridge
from skforecast.ForecasterAutoreg import ForecasterAutoreg
from skforecast.model_selection import backtesting_forecaster
from skforecast.plot import plot_residuals
from skforecast.datasets import fetch_dataset
from skforecast.plot import set_dark_theme
# Download data
# ==============================================================================
data = fetch_dataset(
name="h2o", raw=True, kwargs_read_csv={"names": ["y", "date"], "header": 0}
)
# Data preprocessing
# ==============================================================================
data['date'] = pd.to_datetime(data['date'], format='%Y-%m-%d')
data = data.set_index('date')
data = data.asfreq('MS')
# Plot data
# ==============================================================================
set_dark_theme()
fig, ax=plt.subplots(figsize=(7, 3))
data.plot(ax=ax);
h2o --- Monthly expenditure ($AUD) on corticosteroid drugs that the Australian health system had between 1991 and 2008. Hyndman R (2023). fpp3: Data for Forecasting: Principles and Practice(3rd Edition). http://pkg.robjhyndman.com/fpp3package/,https://github.com/robjhyndman /fpp3package, http://OTexts.com/fpp3. Shape of the dataset: (204, 2)
# Train and backtest forecaster
# ==============================================================================
n_backtest = 36*3
data_train = data[:-n_backtest]
data_test = data[-n_backtest:]
forecaster = ForecasterAutoreg(
regressor = Ridge(),
lags = 5
)
metric, predictions = backtesting_forecaster(
forecaster = forecaster,
y = data.y,
initial_train_size = len(data_train),
steps = 36,
metric = 'mean_squared_error',
verbose = True
)
predictions.head()
Information of backtesting process ---------------------------------- Number of observations used for initial training: 96 Number of observations used for backtesting: 108 Number of folds: 3 Number of steps per fold: 36 Number of steps to exclude from the end of each train set before test (gap): 0 Fold: 0 Training: 1991-07-01 00:00:00 -- 1999-06-01 00:00:00 (n=96) Validation: 1999-07-01 00:00:00 -- 2002-06-01 00:00:00 (n=36) Fold: 1 Training: 1991-07-01 00:00:00 -- 1999-06-01 00:00:00 (n=96) Validation: 2002-07-01 00:00:00 -- 2005-06-01 00:00:00 (n=36) Fold: 2 Training: 1991-07-01 00:00:00 -- 1999-06-01 00:00:00 (n=96) Validation: 2005-07-01 00:00:00 -- 2008-06-01 00:00:00 (n=36)
0%| | 0/3 [00:00<?, ?it/s]
pred | |
---|---|
1999-07-01 | 0.667651 |
1999-08-01 | 0.655759 |
1999-09-01 | 0.652177 |
1999-10-01 | 0.641377 |
1999-11-01 | 0.635245 |
The plot_residuals
function can be used in two ways: with pre-calculated residuals or by passing the predicted and actual values of the series.
# Plot residuals
# ======================================================================================
residuals = predictions['pred'] - data_test['y']
_ = plot_residuals(residuals=residuals, figsize=(7, 3.5))
_ = plot_residuals(y_true=data_test['y'], y_pred=predictions['pred'], figsize=(7, 3.5))
It is possible to customize the plot by by either passing a pre-existing matplotlib figure object or using additional keyword arguments that are passed to matplotlib.pyplot.figure()
.
Plot prediction intervals¶
# Libraries
# ==============================================================================
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.linear_model import Ridge
from skforecast.ForecasterAutoreg import ForecasterAutoreg
from skforecast.model_selection import backtesting_forecaster
from skforecast.datasets import fetch_dataset
from skforecast.plot import set_dark_theme
from skforecast.plot import plot_prediction_intervals
# Data download
# ==============================================================================
data = fetch_dataset(name='h2o_exog', raw=True, verbose=False)
# Data preparation
# ==============================================================================
data = data.rename(columns={'fecha': 'date'})
data['date'] = pd.to_datetime(data['date'], format='%Y-%m-%d')
data = data.set_index('date')
data = data.asfreq('MS')
data = data.sort_index()
# Split data into train-test
# ==============================================================================
steps = 36
data_train = data[:-steps]
data_test = data[-steps:]
print(f"Train dates : {data_train.index.min()} --- {data_train.index.max()} (n={len(data_train)})")
print(f"Test dates : {data_test.index.min()} --- {data_test.index.max()} (n={len(data_test)})")
Train dates : 1992-04-01 00:00:00 --- 2005-06-01 00:00:00 (n=159) Test dates : 2005-07-01 00:00:00 --- 2008-06-01 00:00:00 (n=36)
# Create and train forecaster
# ==============================================================================
forecaster = ForecasterAutoreg(
regressor = Ridge(alpha=0.1, random_state=765),
lags = 15
)
forecaster.fit(y=data_train['y'])
# Prediction intervals
# ==============================================================================
predictions = forecaster.predict_interval(
steps = steps,
interval = [1, 99],
n_boot = 500
)
# Plot forecasts with prediction intervals
# ==============================================================================
plot_prediction_intervals(
predictions = predictions,
y_true = data_test,
target_variable = "y",
title = "Real value vs predicted in test data"
)
Plot correlation between lags of multiple time series¶
When training a Global Forecasting Model of type Dependent multi-series, it is useful to analyze the correlation between the lags of the different time series and the target series. The function skforecast.plot.plot_correlation_lags
creates a heatmap that shows the correlation between the lags of the different time series.
# Libraries
# ==============================================================================
import pandas as pd
import matplotlib.pyplot as plt
from skforecast.datasets import fetch_dataset
from skforecast.plot import plot_multivariate_time_series_corr
from skforecast.utils import multivariate_time_series_corr
# Data download
# ==============================================================================
data = fetch_dataset(name='air_quality_valencia', raw=False, verbose=True)
data
air_quality_valencia -------------------- Hourly measures of several air quimical pollutant (pm2.5, co, no, no2, pm10, nox, o3, so2) at Valencia city. Red de Vigilancia y Control de la Contaminación Atmosférica, 46250054-València - Centre, https://mediambient.gva.es/es/web/calidad-ambiental/datos-historicos. Shape of the dataset: (26304, 10)
pm2.5 | co | no | no2 | pm10 | nox | o3 | veloc. | direc. | so2 | |
---|---|---|---|---|---|---|---|---|---|---|
datetime | ||||||||||
2019-01-01 00:00:00 | 19.0 | 0.2 | 3.0 | 36.0 | 22.0 | 40.0 | 16.0 | 0.5 | 262.0 | 8.0 |
2019-01-01 01:00:00 | 26.0 | 0.1 | 2.0 | 40.0 | 32.0 | 44.0 | 6.0 | 0.6 | 248.0 | 8.0 |
2019-01-01 02:00:00 | 31.0 | 0.1 | 11.0 | 42.0 | 36.0 | 58.0 | 3.0 | 0.3 | 224.0 | 8.0 |
2019-01-01 03:00:00 | 30.0 | 0.1 | 15.0 | 41.0 | 35.0 | 63.0 | 3.0 | 0.2 | 220.0 | 10.0 |
2019-01-01 04:00:00 | 30.0 | 0.1 | 16.0 | 39.0 | 36.0 | 63.0 | 3.0 | 0.4 | 221.0 | 11.0 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
2021-12-31 19:00:00 | 31.0 | 0.1 | 20.0 | 36.0 | 34.0 | 66.0 | 13.0 | 0.1 | 87.0 | 3.0 |
2021-12-31 20:00:00 | 33.0 | 0.1 | 25.0 | 38.0 | 39.0 | 75.0 | 13.0 | 0.1 | 67.0 | 4.0 |
2021-12-31 21:00:00 | 34.0 | 0.1 | 24.0 | 36.0 | 42.0 | 73.0 | 13.0 | 0.1 | 84.0 | 5.0 |
2021-12-31 22:00:00 | 43.0 | 0.1 | 22.0 | 32.0 | 50.0 | 66.0 | 14.0 | 0.1 | 112.0 | 5.0 |
2021-12-31 23:00:00 | 50.0 | 0.1 | 22.0 | 28.0 | 57.0 | 61.0 | 13.0 | 0.1 | 74.0 | 3.0 |
26304 rows × 10 columns
# Correlation between target series and the lags of the other series
# ======================================================================================
corr = multivariate_time_series_corr(
time_series = data['pm2.5'],
other = data,
lags = 24
)
corr.head(3)
pm2.5 | co | no | no2 | pm10 | nox | o3 | veloc. | direc. | so2 | |
---|---|---|---|---|---|---|---|---|---|---|
lag | ||||||||||
0 | 1.000000 | 0.162926 | 0.354571 | 0.526002 | 0.742242 | 0.490614 | -0.349984 | -0.207674 | 0.015281 | 0.156599 |
1 | 0.947931 | 0.166266 | 0.333870 | 0.515745 | 0.697067 | 0.472367 | -0.334106 | -0.221082 | 0.002978 | 0.141813 |
2 | 0.885050 | 0.159302 | 0.290982 | 0.485289 | 0.643001 | 0.429932 | -0.300287 | -0.223318 | -0.011300 | 0.120706 |
_ = plot_multivariate_time_series_corr(corr, figsize=(7, 7), )