awslabs / gluonts

Probabilistic time series modeling in Python
https://ts.gluon.ai
Apache License 2.0
4.52k stars 744 forks source link

How to reduce the width of prediction intervals ? #1203

Open parimuns opened 3 years ago

parimuns commented 3 years ago

Hello I am using DeepAR for my dataset and I am obtaining results with DeepAR which have very "wide coverage".I want to reduce the width of prediction intervals which I am not able to understand that which parameters should I tune, so that I obtain PI with narrow width and better coverage.I am attaching code for reference paper and I am also attaching the image of my results and the image of result which is desired.


!pip install gluonts==0.5.2
import mxnet as mx
import gluonts
# import time
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import json
import os
from itertools import islice
from pathlib import Path

from gluonts.dataset.field_names import FieldName

[f"FieldName.{k} = '{v}'" for k, v in FieldName.__dict__.items() if not k.startswith('_')]

wind_train = pd.read_csv(r'GROUP A.csv',parse_dates=[['Date', 'Time']],header=0,index_col=0)
wind_train.head()

train=wind_train.transpose()
train.head()

from gluonts.dataset.common import ListDataset

train2=train.to_numpy()
type(train2)
train2.shape

feat_static_cat=train2[:,0]
feat_static_cat.shape

# feat_dynamic_real=train2[[1,3,5,7,9,11,13,15],:]
# feat_dynamic_real.shape

target=train2
target.shape

freq='5min'
prediction_length=12
start= [pd.Timestamp("2012-01-01", freq='5min') 
                                for _ in range(22)]

train_ds = ListDataset([{FieldName.TARGET: target, 
                         FieldName.START: start,
                        #  FieldName.FEAT_DYNAMIC_REAL: [fdr],
                         FieldName.FEAT_STATIC_CAT: [fsc]} 
                        for (target, start,fsc) in zip(target[:, :-prediction_length], 
                                                            start, 
                                                            #  feat_dynamic_real[:, :-prediction_length], 
                                                             feat_static_cat)],
                      freq=freq)

from gluonts.model.deepar import DeepAREstimator
from gluonts.trainer import Trainer
from gluonts.distribution import MultivariateGaussianOutput
from gluonts.distribution import NegativeBinomialOutput
from gluonts.distribution import GaussianOutput
from gluonts.distribution import BetaOutput
from gluonts.distribution import LogitNormalOutput
from gluonts.distribution import StudentTOutput

from gluonts.time_feature import HourOfDay
t2=HourOfDay(True)

# from gluonts.dataset.multivariate_grouper import MultivariateGrouper

# grouper_train = MultivariateGrouper(max_target_dim=22)

# train_ds = grouper_train(train_ds)

estimator=DeepAREstimator(freq='5min',
        prediction_length=12,
        context_length=12,
        cardinality=[11],
        distr_output = LogitNormalOutput(),
        scaling=True,
        trainer = Trainer(
            epochs=2, num_batches_per_epoch=64, hybridize=False),
        num_layers= 2,
        num_cells= 40,
        cell_type= "lstm",
        num_parallel_samples = 100,
        dropout_rate= 0.1,
        use_feat_dynamic_real = False,
        use_feat_static_cat = True,
        time_features=[t2]
    )

# start = time.time()

predictor = estimator.train(train_ds)

# end = time.time()

# print(f"Runtime of the program is {end - start}")

from gluonts.evaluation.backtest import make_evaluation_predictions

test_ds = ListDataset([{FieldName.TARGET: target, 
                        FieldName.START: start,
                        # FieldName.FEAT_DYNAMIC_REAL: [fdr],
                        FieldName.FEAT_STATIC_CAT: [fsc]} 
                       for (target,start,fsc) in zip(target, 
                                                            start, 
                                                            # feat_dynamic_real, 
                                                          feat_static_cat)],
                     freq=freq)

# grouper_test = MultivariateGrouper(max_target_dim=8)
# test_ds = grouper_test(test_ds)

len(test_ds)

forecast_it, ts_it = make_evaluation_predictions(
    dataset=test_ds,  # test dataset
    predictor=predictor,  # predictor
    num_samples=100,  # number of sample paths we want for evaluation
)

forecasts = list(forecast_it)
tss = list(ts_it)

def plot_prob_forecasts(ts_entry, forecast_entry):
    plot_length = 150
    prediction_intervals = (90.0, 95.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='r')
    plt.grid(which="both")
    plt.legend(legend, loc="upper left")
    plt.show()

plot_prob_forecasts(tss[0], forecasts[0])

from gluonts.evaluation import Evaluator

from gluonts.evaluation import MultivariateEvaluator

len(test_ds)

forecast_it, ts_it = make_evaluation_predictions(
    dataset=test_ds,  
    predictor=predictor,  
    num_samples=100
    )

quantile_seq = np.arange(0.01, 0.99 , .01)
evaluator = Evaluator(quantiles=quantile_seq)
agg_metrics, item_metrics = evaluator(iter(tss), iter(forecasts), num_series=len(test_ds))

print(json.dumps(agg_metrics, indent=4))

'''
![desired PI](https://user-images.githubusercontent.com/7879246/101398002-740ab800-38f3-11eb-8aeb-e35a86a66fae.jpg)
![obtained prediction intervals](https://user-images.githubusercontent.com/7879246/101398023-7cfb8980-38f3-11eb-8dd8-ddc87394f84c.png)

[GROUP A.zip](https://github.com/awslabs/gluon-ts/files/5654943/GROUP.A.zip)
StatMixedML commented 3 years ago

Not sure what data you are working on and whether or not the LogitNormalOutput() is an appropriate choice for your data. Misspecifying the distribution can result in too wide / too narrow prediction intervals with bad coverage.

parimuns commented 3 years ago

@StatMixedML .I agree with your point. I am working on wind data and this data is best fitted using logitnormal distributions as per research papers (in comparison to gaussian and beta) . I tried tuning parameters like number of cells of lstm ,batch size,number of layers but couldn't get effective results.Is there any parameter which I am missing that may give a significant improvement in results ? I am tuning parameters by trial and error method as dataset is huge ,tuning by grid search may take large time and memory.If there is any other way,please let me know.

StatMixedML commented 3 years ago

Can you please share a density plot of your data + some forecasts with corresponding prediction intervals + the coverage. Unfortunately, I cannot see you attachments.