Table Of Contents
Table Of Contents

[Download]

Quick Start Tutorial

The GluonTS toolkit contains components and tools for building time series models using MXNet. The models that are currently included are forecasting models but the components also support other time series use cases, such as classification or anomaly detection.

The toolkit is not intended as a forecasting solution for businesses or end users but it rather targets scientists and engineers who want to tweak algorithms or build and experiment with their own models.

GluonTS contains:

  • Components for building new models (likelihoods, feature processing pipelines, calendar features etc.)
  • Data loading and processing
  • A number of pre-built models
  • Plotting and evaluation facilities
  • Artificial and real datasets (only external datasets with blessed license)
In [1]:
# Third-party imports
%matplotlib inline
import mxnet as mx
from mxnet import gluon
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import json

Datasets

GluonTS datasets

GluonTS comes with a number of publicly available datasets.

In [2]:
from gluonts.dataset.repository.datasets import get_dataset, dataset_recipes
from gluonts.dataset.util import to_pandas
In [3]:
print(f"Available datasets: {list(dataset_recipes.keys())}")
Available datasets: ['constant', 'exchange_rate', 'solar-energy', 'electricity', 'traffic', 'm4_hourly', 'm4_daily', 'm4_weekly', 'm4_monthly', 'm4_quarterly', 'm4_yearly']

To download one of the built-in datasets, simply call get_dataset with one of the above names. GluonTS can re-use the saved dataset so that it does not need to be downloaded again: simply set regenerate=False.

In [4]:
dataset = get_dataset("m4_hourly", regenerate=True)
INFO:root:downloading and processing m4_hourly
saving time-series into /var/lib/jenkins/.mxnet/gluon-ts/datasets/m4_hourly/train/data.json
saving time-series into /var/lib/jenkins/.mxnet/gluon-ts/datasets/m4_hourly/test/data.json

In general, the datasets provided by GluonTS are objects that consists of three main members:

  • dataset.train is an iterable collection of data entries used for training. Each entry corresponds to one time series
  • dataset.test is an iterable collection of data entries used for inference. The test dataset is an extended version of the train dataset that contains a window in the end of each time series that was not seen during training. This window has length equal to the recommended prediction length.
  • dataset.metadata contains metadata of the dataset such as the frequency of the time series, a recommended prediction horizon, associated features, etc.
In [5]:
entry = next(iter(dataset.train))
train_series = to_pandas(entry)
train_series.plot()
plt.grid(which="both")
plt.legend(["train series"], loc="upper left")
plt.show()
../../_images/examples_basic_forecasting_tutorial_tutorial_8_0.png
In [6]:
entry = next(iter(dataset.test))
test_series = to_pandas(entry)
test_series.plot()
plt.axvline(train_series.index[-1], color='r') # end of train dataset
plt.grid(which="both")
plt.legend(["test series", "end of train series"], loc="upper left")
plt.show()
../../_images/examples_basic_forecasting_tutorial_tutorial_9_0.png
In [7]:
print(f"Length of forecasting window in test dataset: {len(test_series) - len(train_series)}")
print(f"Recommended prediction horizon: {dataset.metadata.prediction_length}")
print(f"Frequency of the time series: {dataset.metadata.freq}")
Length of forecasting window in test dataset: 48
Recommended prediction horizon: 48
Frequency of the time series: H

Custom datasets

At this point, it is important to emphasize that GluonTS does not require this specific format for a custom dataset that a user may have. The only requirements for a custom dataset are to be iterable and have a “target” and a “start” field. To make this more clear, assume the common case where a dataset is in the form of a numpy.array and the index of the time series in a pandas.Timestamp (possibly different for each time series):

In [8]:
N = 10  # number of time series
T = 100  # number of timesteps
prediction_length = 24
freq = "1H"
custom_dataset = np.random.normal(size=(N, T))
start = pd.Timestamp("01-01-2019", freq=freq)  # can be different for each time series

Now, you can split your dataset and bring it in a GluonTS appropriate format with just two lines of code:

In [9]:
from gluonts.dataset.common import ListDataset
In [10]:
# train dataset: cut the last window of length "prediction_length", add "target" and "start" fields
train_ds = ListDataset([{'target': x, 'start': start}
                        for x in custom_dataset[:, :-prediction_length]],
                       freq=freq)
# test dataset: use the whole dataset, add "target" and "start" fields
test_ds = ListDataset([{'target': x, 'start': start}
                       for x in custom_dataset],
                      freq=freq)

Training an existing model (Estimator)

GluonTS comes with a number of pre-built models. All the user needs to do is configure some hyperparameters. The existing models focus on (but are not limited to) probabilistic forecasting. Probabilistic forecasts are predictions in the form of a probability distribution, rather than simply a single point estimate.

We will begin with GulonTS’s pre-built feedforward neural network estimator, a simple but powerful forecasting model. We will use this model to demonstrate the process of training a model, producing forecasts, and evaluating the results.

GluonTS’s built-in feedforward neural network (SimpleFeedForwardEstimator) accepts an input window of length context_length and predicts the distribution of the values of the subsequent prediction_length values. In GluonTS parlance, the feedforward neural network model is an example of Estimator. In GluonTS, Estimator objects represent a forecasting model as well as details such as its coefficients, weights, etc.

In general, each estimator (pre-built or custom) is configured by a number of hyperparameters that can be either common (but not binding) among all estimators (e.g., the prediction_length) or specific for the particular estimator (e.g., number of layers for a neural network or the stride in a CNN).

Finally, each estimator is configured by a Trainer, which defines how the model will be trained i.e., the number of epochs, the learning rate, etc.

In [11]:
from gluonts.model.simple_feedforward import SimpleFeedForwardEstimator
from gluonts.trainer import Trainer
INFO:root:Using GPU
In [12]:
estimator = SimpleFeedForwardEstimator(
    num_hidden_dimensions=[10],
    prediction_length=dataset.metadata.prediction_length,
    context_length=100,
    freq=dataset.metadata.freq,
    trainer=Trainer(ctx="cpu",
                    epochs=5,
                    learning_rate=1e-3,
                    num_batches_per_epoch=100
                   )
)

After specifying our estimator with all the necessary hyperparameters we can train it using our training dataset dataset.train by invoking the train method of the estimator. The training algorithm returns a fitted model (or a Predictor in GluonTS parlance) that can be used to construct forecasts.

In [13]:
predictor = estimator.train(dataset.train)
INFO:root:Start model training
INFO:root:Epoch[0] Learning rate is 0.001
  0%|          | 0/100 [00:00<?, ?it/s]INFO:root:Number of parameters in SimpleFeedForwardTrainingNetwork: 48513
100%|██████████| 100/100 [00:00<00:00, 155.36it/s, avg_epoch_loss=5.34]
INFO:root:Epoch[0] Elapsed time 0.646 seconds
INFO:root:Epoch[0] Evaluation metric 'epoch_loss'=5.344220
INFO:root:Epoch[1] Learning rate is 0.001
100%|██████████| 100/100 [00:00<00:00, 170.15it/s, avg_epoch_loss=4.74]
INFO:root:Epoch[1] Elapsed time 0.589 seconds
INFO:root:Epoch[1] Evaluation metric 'epoch_loss'=4.743799
INFO:root:Epoch[2] Learning rate is 0.001
100%|██████████| 100/100 [00:00<00:00, 176.00it/s, avg_epoch_loss=4.71]
INFO:root:Epoch[2] Elapsed time 0.570 seconds
INFO:root:Epoch[2] Evaluation metric 'epoch_loss'=4.706627
INFO:root:Epoch[3] Learning rate is 0.001
100%|██████████| 100/100 [00:00<00:00, 163.91it/s, avg_epoch_loss=4.6]
INFO:root:Epoch[3] Elapsed time 0.619 seconds
INFO:root:Epoch[3] Evaluation metric 'epoch_loss'=4.597967
INFO:root:Epoch[4] Learning rate is 0.001
100%|██████████| 100/100 [00:00<00:00, 102.74it/s, avg_epoch_loss=4.65]
INFO:root:Epoch[4] Elapsed time 0.980 seconds
INFO:root:Epoch[4] Evaluation metric 'epoch_loss'=4.653066
INFO:root:Loading parameters from best epoch (3)
INFO:root:Final loss: 4.597966635227204 (occurred at epoch 3)
INFO:root:End model training

With a predictor in hand, we can now predict the last window of the dataset.test and evaluate our model’s performance.

GluonTS comes with the make_evaluation_predictions function that automates the process of prediction and model evaluation. Roughly, this function performs the following steps:

  • Removes the final window of length prediction_length of the dataset.test that we want to predict
  • The estimator uses the remaining data to predict (in the form of sample paths) the “future” window that was just removed
  • The module outputs the forecast sample paths and the dataset.test (as python generator objects)
In [14]:
from gluonts.evaluation.backtest import make_evaluation_predictions
In [15]:
forecast_it, ts_it = make_evaluation_predictions(
    dataset=dataset.test,  # test dataset
    predictor=predictor,  # predictor
    num_samples=100,  # number of sample paths we want for evaluation
)

First, we can convert these generators to lists to ease the subsequent computations.

In [16]:
forecasts = list(forecast_it)
tss = list(ts_it)

We can examine the first element of these lists (that corresponds to the first time series of the dataset). Let’s start with the list containing the time series, i.e., tss. We expect the first entry of tss to contain the (target of the) first time series of dataset.test.

In [17]:
# first entry of the time series list
ts_entry = tss[0]
In [18]:
# first 5 values of the time series (convert from pandas to numpy)
np.array(ts_entry[:5]).reshape(-1,)
Out[18]:
array([605., 586., 586., 559., 511.], dtype=float32)
In [19]:
# first entry of dataset.test
dataset_test_entry = next(iter(dataset.test))
In [20]:
# first 5 values
dataset_test_entry['target'][:5]
Out[20]:
array([605., 586., 586., 559., 511.], dtype=float32)

The entries in the forecast list are a bit more complex. They are objects that contain all the sample paths in the form of numpy.ndarray with dimension (num_samples, prediction_length), the start date of the forecast, the frequency of the time series, etc. We can access all these information by simply invoking the corresponding attribute of the forecast object.

In [21]:
# first entry of the forecast list
forecast_entry = forecasts[0]
In [22]:
print(f"Number of sample paths: {forecast_entry.num_samples}")
print(f"Dimension of samples: {forecast_entry.samples.shape}")
print(f"Start date of the forecast window: {forecast_entry.start_date}")
print(f"Frequency of the time series: {forecast_entry.freq}")
Number of sample paths: 100
Dimension of samples: (100, 48)
Start date of the forecast window: 1750-01-30 04:00:00
Frequency of the time series: H

We can also do calculations to summarize the sample paths, such computing the mean or a quantile for each of the 48 time steps in the forecast window.

In [23]:
print(f"Mean of the future window:\n {forecast_entry.mean}")
print(f"0.5-quantile (median) of the future window:\n {forecast_entry.quantile(0.5)}")
Mean of the future window:
 [620.0515  537.17554 485.5743  509.64212 520.8163  477.86136 433.08478
 550.6449  551.67554 581.70465 625.45447 709.7216  787.1506  841.0209
 844.37994 833.6051  896.8868  864.22906 868.94604 825.3437  881.78876
 766.8772  792.6513  658.1629  619.3651  544.6366  536.1047  513.6892
 558.0323  582.9893  472.81488 501.83362 566.8247  622.5814  678.56537
 692.5449  781.4854  860.89197 894.003   914.9668  919.4763  857.2972
 866.8959  833.71814 929.57275 771.93994 726.2421  712.1329 ]
0.5-quantile (median) of the future window:
 [628.17035 537.75464 503.38824 512.10834 513.04236 482.36304 441.48663
 551.5678  558.97614 559.0917  617.93805 700.7184  798.8377  856.24774
 850.71    848.22876 872.4481  852.89716 859.079   826.2301  878.2653
 768.13    781.21014 647.89813 612.65826 543.3427  538.32086 515.72217
 550.19653 566.2625  443.41754 493.74854 564.6247  622.6069  678.43207
 681.9369  771.52094 877.1313  890.73706 930.8169  893.2791  861.73926
 877.58704 834.0515  905.16614 776.9636  730.2659  705.1811 ]

Forecast objects have a plot method that can summarize the forecast paths as the mean, prediction intervals, etc. The prediction intervals are shaded in different colors as a “fan chart”.

In [24]:
def plot_prob_forecasts(ts_entry, forecast_entry):
    plot_length = 150
    prediction_intervals = (50.0, 90.0)
    legend = ["observations", "median prediction"] + [f"{k}% prediction interval" for k in prediction_intervals][::-1]

    fig, ax = plt.subplots(1, 1, figsize=(10, 7))
    ts_entry[-plot_length:].plot(ax=ax)  # plot the time series
    forecast_entry.plot(prediction_intervals=prediction_intervals, color='g')
    plt.grid(which="both")
    plt.legend(legend, loc="upper left")
    plt.show()
In [25]:
plot_prob_forecasts(ts_entry, forecast_entry)
../../_images/examples_basic_forecasting_tutorial_tutorial_38_0.png

We can also evaluate the quality of our forecasts numerically. In GluonTS, the Evaluator class can compute aggregate performance metrics, as well as metrics per time series (which can be useful for analyzing performance across heterogeneous time series).

In [26]:
from gluonts.evaluation import Evaluator
In [27]:
evaluator = Evaluator(quantiles=[0.1, 0.5, 0.9])
agg_metrics, item_metrics = evaluator(iter(tss), iter(forecasts), num_series=len(dataset.test))
Running evaluation: 100%|██████████| 414/414 [00:01<00:00, 231.09it/s]

Aggregate metrics aggregate both across time-steps and across time series.

In [28]:
print(json.dumps(agg_metrics, indent=4))
{
    "MSE": 11864008.850155808,
    "abs_error": 10692023.52798462,
    "abs_target_sum": 145558863.59960938,
    "abs_target_mean": 7324.822041043146,
    "seasonal_error": 336.9046924038305,
    "MASE": 3.723827143015013,
    "sMAPE": 0.19349319981922775,
    "MSIS": 34.00009564095166,
    "QuantileLoss[0.1]": 4037133.1970169074,
    "Coverage[0.1]": 0.11659621578099838,
    "QuantileLoss[0.5]": 10692023.627287865,
    "Coverage[0.5]": 0.5409118357487923,
    "QuantileLoss[0.9]": 6787315.674976348,
    "Coverage[0.9]": 0.8678039452495973,
    "RMSE": 3444.41705520046,
    "NRMSE": 0.4702390086612851,
    "ND": 0.07345498077942753,
    "wQuantileLoss[0.1]": 0.02773539925484649,
    "wQuantileLoss[0.5]": 0.07345498146164806,
    "wQuantileLoss[0.9]": 0.046629353287933765,
    "mean_wQuantileLoss": 0.049273244668142764,
    "MAE_Coverage": 0.029901368760064485
}

Individual metrics are aggregated only across time-steps.

In [29]:
item_metrics.head()
Out[29]:
item_id MSE abs_error abs_target_sum abs_target_mean seasonal_error MASE sMAPE MSIS QuantileLoss[0.1] Coverage[0.1] QuantileLoss[0.5] Coverage[0.5] QuantileLoss[0.9] Coverage[0.9]
0 NaN 3805.291667 2404.578613 31644.0 659.250000 42.371302 1.182295 0.074700 5.344860 720.684784 0.020833 2404.578796 0.729167 1389.871069 1.000000
1 NaN 213818.270833 19659.789062 124149.0 2586.437500 165.107988 2.480673 0.152496 18.527966 5628.736304 0.375000 19659.789429 0.979167 8439.479199 1.000000
2 NaN 29668.088542 6497.687988 65030.0 1354.791667 78.889053 1.715935 0.096159 14.143526 3074.146228 0.000000 6497.687805 0.250000 2575.898437 0.750000
3 NaN 171173.593750 16995.941406 235783.0 4912.145833 258.982249 1.367206 0.071583 6.992693 7442.862891 0.041667 16995.942627 0.500000 7767.566309 0.979167
4 NaN 125729.895833 12895.285156 131088.0 2731.000000 200.494083 1.339949 0.092403 8.639644 4587.205273 0.125000 12895.284302 0.791667 7177.441553 1.000000
In [30]:
item_metrics.plot(x='MSIS', y='MASE', kind='scatter')
plt.grid(which="both")
plt.show()
../../_images/examples_basic_forecasting_tutorial_tutorial_46_0.png

Create your own forecast model

For creating your own forecast model you need to:

  • Define the training and prediction network
  • Define a new estimator that specifies any data processing and uses the networks

The training and prediction networks can be arbitrarily complex but they should follow some basic rules:

  • Both should have a hybrid_forward method that defines what should happen when the network is called
  • The training network’s hybrid_forward should return a loss based on the prediction and the true values
  • The prediction network’s hybrid_forward should return the predictions

For example, we can create a simple training network that defines a neural network which takes as an input the past values of the time series and outputs a future predicted window of length prediction_length. It uses the L1 loss in the hybrid_forward method to evaluate the error among the predictions and the true values of the time series. The corresponding prediction network should be identical to the training network in terms of architecture (we achieve this by inheriting the training network class), and its hybrid_forward method outputs directly the predictions.

Note that this simple model does only point forecasts by construction, i.e., we train it to outputs directly the future values of the time series and not any probabilistic view of the future (to achieve this we should train a network to learn a probability distribution and then sample from it to create sample paths).

In [31]:
class MyTrainNetwork(gluon.HybridBlock):
    def __init__(self, prediction_length, **kwargs):
        super().__init__(**kwargs)
        self.prediction_length = prediction_length

        with self.name_scope():
            # Set up a 3 layer neural network that directly predicts the target values
            self.nn = mx.gluon.nn.HybridSequential()
            self.nn.add(mx.gluon.nn.Dense(units=40, activation='relu'))
            self.nn.add(mx.gluon.nn.Dense(units=40, activation='relu'))
            self.nn.add(mx.gluon.nn.Dense(units=self.prediction_length, activation='softrelu'))

    def hybrid_forward(self, F, past_target, future_target):
        prediction = self.nn(past_target)
        # calculate L1 loss with the future_target to learn the median
        return (prediction - future_target).abs().mean(axis=-1)


class MyPredNetwork(MyTrainNetwork):
    # The prediction network only receives past_target and returns predictions
    def hybrid_forward(self, F, past_target):
        prediction = self.nn(past_target)
        return prediction.expand_dims(axis=1)

Now, we need to construct the estimator which should also follow some rules:

  • It should include a create_transformation method that defines all the possible feature transformations and how the data is split during training
  • It should include a create_training_network method that returns the training network configured with any necessary hyperparameters
  • It should include a create_predictor method that creates the prediction network, and returns a Predictor object

A Predictor defines the predict method of a given predictor. Roughly, this method takes the test dataset, it passes it through the prediction network and yields the predictions. You can think of the Predictor object as a wrapper of the prediction network that defines its predict method.

Earlier, we used the make_evaluation_predictions to evaluate our predictor. Internally, the make_evaluation_predictions function invokes the predict method of the predictor to get the forecasts.

In [32]:
from gluonts.model.estimator import GluonEstimator
from gluonts.model.predictor import Predictor, RepresentableBlockPredictor
from gluonts.core.component import validated
from gluonts.support.util import copy_parameters
from gluonts.transform import ExpectedNumInstanceSampler, Transformation, InstanceSplitter
from gluonts.dataset.field_names import FieldName
from mxnet.gluon import HybridBlock
In [33]:
class MyEstimator(GluonEstimator):
    @validated()
    def __init__(
        self,
        freq: str,
        context_length: int,
        prediction_length: int,
        trainer: Trainer = Trainer()
    ) -> None:
        super().__init__(trainer=trainer)
        self.context_length = context_length
        self.prediction_length = prediction_length
        self.freq = freq


    def create_transformation(self):
        # Feature transformation that the model uses for input.
        # Here we use a transformation that randomly select training samples from all time series.
        return InstanceSplitter(
                    target_field=FieldName.TARGET,
                    is_pad_field=FieldName.IS_PAD,
                    start_field=FieldName.START,
                    forecast_start_field=FieldName.FORECAST_START,
                    train_sampler=ExpectedNumInstanceSampler(num_instances=1),
                    past_length=self.context_length,
                    future_length=self.prediction_length,
                )

    def create_training_network(self) -> MyTrainNetwork:
        return MyTrainNetwork(
            prediction_length=self.prediction_length
        )

    def create_predictor(
        self, transformation: Transformation, trained_network: HybridBlock
    ) -> Predictor:
        prediction_network = MyPredNetwork(
            prediction_length=self.prediction_length
        )

        copy_parameters(trained_network, prediction_network)

        return RepresentableBlockPredictor(
            input_transform=transformation,
            prediction_net=prediction_network,
            batch_size=self.trainer.batch_size,
            freq=self.freq,
            prediction_length=self.prediction_length,
            ctx=self.trainer.ctx,
        )
INFO:root:Using GPU

Now, we can repeat the same pipeline as in the case we had a pre-built model: train the predictor, create the forecasts and evaluate the results.

In [34]:
estimator = MyEstimator(
    prediction_length=dataset.metadata.prediction_length,
    context_length=100,
    freq=dataset.metadata.freq,
    trainer=Trainer(ctx="cpu",
                    epochs=5,
                    learning_rate=1e-3,
                    num_batches_per_epoch=100
                   )
)
In [35]:
predictor = estimator.train(dataset.train)
INFO:root:Start model training
INFO:root:Epoch[0] Learning rate is 0.001
  0%|          | 0/100 [00:00<?, ?it/s]INFO:root:Number of parameters in MyTrainNetwork: 7648
100%|██████████| 100/100 [00:00<00:00, 217.13it/s, avg_epoch_loss=2.43e+3]
INFO:root:Epoch[0] Elapsed time 0.462 seconds
INFO:root:Epoch[0] Evaluation metric 'epoch_loss'=2432.226144
INFO:root:Epoch[1] Learning rate is 0.001
100%|██████████| 100/100 [00:00<00:00, 215.21it/s, avg_epoch_loss=1.26e+3]
INFO:root:Epoch[1] Elapsed time 0.466 seconds
INFO:root:Epoch[1] Evaluation metric 'epoch_loss'=1259.024672
INFO:root:Epoch[2] Learning rate is 0.001
100%|██████████| 100/100 [00:00<00:00, 208.83it/s, avg_epoch_loss=1.02e+3]
INFO:root:Epoch[2] Elapsed time 0.481 seconds
INFO:root:Epoch[2] Evaluation metric 'epoch_loss'=1023.188023
INFO:root:Epoch[3] Learning rate is 0.001
100%|██████████| 100/100 [00:00<00:00, 210.66it/s, avg_epoch_loss=698]
INFO:root:Epoch[3] Elapsed time 0.477 seconds
INFO:root:Epoch[3] Evaluation metric 'epoch_loss'=698.246794
INFO:root:Epoch[4] Learning rate is 0.001
100%|██████████| 100/100 [00:00<00:00, 211.34it/s, avg_epoch_loss=582]
INFO:root:Epoch[4] Elapsed time 0.475 seconds
INFO:root:Epoch[4] Evaluation metric 'epoch_loss'=582.361171
INFO:root:Loading parameters from best epoch (4)
INFO:root:Final loss: 582.3611713981628 (occurred at epoch 4)
INFO:root:End model training
In [36]:
forecast_it, ts_it = make_evaluation_predictions(
    dataset=dataset.test,
    predictor=predictor,
    num_samples=100
)
In [37]:
forecasts = list(forecast_it)
tss = list(ts_it)
In [38]:
plot_prob_forecasts(tss[0], forecasts[0])
../../_images/examples_basic_forecasting_tutorial_tutorial_57_0.png

Observe that we cannot actually see any prediction intervals in the predictions. This is expected since the model that we defined does not do probabilistic forecasting but it just gives point estimates. By requiring 100 sample paths (defined in make_evaluation_predictions) in such a network, we get 100 times the same output.

In [39]:
evaluator = Evaluator(quantiles=[0.1, 0.5, 0.9])
agg_metrics, item_metrics = evaluator(iter(tss), iter(forecasts), num_series=len(dataset.test))
Running evaluation: 100%|██████████| 414/414 [00:01<00:00, 250.28it/s]
In [40]:
print(json.dumps(agg_metrics, indent=4))
{
    "MSE": 8973385.115875939,
    "abs_error": 10200268.643632889,
    "abs_target_sum": 145558863.59960938,
    "abs_target_mean": 7324.822041043146,
    "seasonal_error": 336.9046924038305,
    "MASE": 4.297092968900404,
    "sMAPE": 0.22321967848964028,
    "MSIS": 171.88372031450206,
    "QuantileLoss[0.1]": 10763964.097241687,
    "Coverage[0.1]": 0.48601046698872796,
    "QuantileLoss[0.5]": 10200268.777292728,
    "Coverage[0.5]": 0.48601046698872796,
    "QuantileLoss[0.9]": 9636573.45734377,
    "Coverage[0.9]": 0.48601046698872796,
    "RMSE": 2995.560901713724,
    "NRMSE": 0.4089602293309939,
    "ND": 0.07007658888908956,
    "wQuantileLoss[0.1]": 0.07394921773262987,
    "wQuantileLoss[0.5]": 0.0700765898073424,
    "wQuantileLoss[0.9]": 0.06620396188205492,
    "mean_wQuantileLoss": 0.0700765898073424,
    "MAE_Coverage": 0.2713298443370907
}
In [41]:
item_metrics.head(10)
Out[41]:
item_id MSE abs_error abs_target_sum abs_target_mean seasonal_error MASE sMAPE MSIS QuantileLoss[0.1] Coverage[0.1] QuantileLoss[0.5] Coverage[0.5] QuantileLoss[0.9] Coverage[0.9]
0 NaN 4.141526e+03 2419.749512 31644.0 659.250000 42.371302 1.189755 0.079948 47.590179 2195.262140 0.458333 2419.749420 0.458333 2644.236700 0.458333
1 NaN 1.197934e+05 13539.279297 124149.0 2586.437500 165.107988 1.708387 0.098435 68.335477 22975.300903 0.791667 13539.279907 0.791667 4103.258911 0.791667
2 NaN 3.906835e+04 7683.803223 65030.0 1354.791667 78.889053 2.029169 0.116466 81.166765 2308.402234 0.187500 7683.803162 0.187500 13059.204089 0.187500
3 NaN 2.932830e+05 21245.980469 235783.0 4912.145833 258.982249 1.709092 0.096224 68.363699 11760.985791 0.229167 21245.979736 0.229167 30730.973682 0.229167
4 NaN 9.961122e+04 11188.831055 131088.0 2731.000000 200.494083 1.162631 0.082200 46.505243 14726.384741 0.625000 11188.830933 0.625000 7651.277124 0.625000
5 NaN 1.805975e+05 16349.147461 303379.0 6320.395833 212.875740 1.600028 0.056029 64.001136 17643.888086 0.645833 16349.147461 0.645833 15054.406836 0.645833
6 NaN 8.300847e+06 110123.953125 1985325.0 41360.937500 1947.687870 1.177935 0.060050 47.117385 58304.443359 0.333333 110123.951172 0.333333 161943.458984 0.333333
7 NaN 8.028310e+06 108575.765625 1540706.0 32098.041667 1624.044379 1.392816 0.075408 55.712641 52950.816016 0.250000 108575.767578 0.250000 164200.719141 0.250000
8 NaN 9.088239e+06 120052.664062 1640860.0 34184.583333 1850.988166 1.351223 0.070286 54.048912 158539.874219 0.604167 120052.667969 0.604167 81565.461719 0.604167
9 NaN 8.491302e+02 1116.077881 21408.0 446.000000 10.526627 2.208839 0.054473 88.353555 449.810010 0.270833 1116.077881 0.270833 1782.345752 0.270833
In [42]:
item_metrics.plot(x='MSIS', y='MASE', kind='scatter')
plt.grid(which="both")
plt.show()
../../_images/examples_basic_forecasting_tutorial_tutorial_62_0.png