2

I am trying to use the tutorial here, where we have two covariates to predict the target.

The tutorial uses .stack() to add two covariates together. It is not clear to me how to use this function to add more than two covariates to the model.

I tried the following code:

from darts.models import BlockRNNModel


my_covariate = (tg.sine_timeseries(length=LENGTH, 
                                value_frequency=(1/14), 
                                freq='D', 
                                column_name='my_covariate')
             + 0.4 * tg.gaussian_timeseries(length=LENGTH, freq='D'))


brnn_melting_and_rain = BlockRNNModel(input_chunk_length=30, 
                                      output_chunk_length=10, 
                                      n_rnn_layers=2)

brnn_melting_and_rain.fit(flow_train, 
                          # past_covariates=melting.stack(rainfalls).stack(rainfalls), 
                          past_covariates=[melting,rainfalls,my_covariate],
                          epochs=10, 
                          verbose=True)

eval_model(brnn_melting_and_rain, 
           past_covariates=melting.stack(rainfalls))

But I got the following error:

ValueError: The provided sequence of target series must have the same length as the provided sequence of covariate series.

I tried reading the documentation of DARTS, but there is no clear direction on how to use past_covariates, in specific, what is the data type I should pass here and if there are any other requirements.

M.M
  • 1,343
  • 7
  • 20
  • 49

3 Answers3

3

Use API's concatenate to stack many time series properly, rather than passing a list or invoking many stack calls (e.g. avoid "stacking stack").

For instance, build the multivariate data along with your custom features this way

from darts import concatenate
past_covariates = concatenate([melting, rainfalls, my_covariate], axis=1)
past_covariates
inspect visually

enter image description here and then train on this multivariate time series

brnn_melting.fit(flow_train, 
                 past_covariates=past_covariates, 
                 epochs=100, 
                 verbose=True)

Note: although not recommended, "stacking stack" is essentially equivalent to concatenation

from darts import concatenate

past_covariates = concatenate([melting, rainfalls, my_covariate], axis=1)
past_covariates_old = melting.stack(rainfalls).stack(my_covariate)
assert past_covariates == past_covariates_old
Maciej Skorski
  • 2,303
  • 6
  • 14
0

Copy pasting from your code and from the link you provide I've managed to get a working code (no error) but I'm not sure that's what you want.

from darts.models import BlockRNNModel
from darts.utils import timeseries_generation as tg
from darts.metrics import rmse


def eval_model(model, past_covariates=None, future_covariates=None):
    # Past and future covariates are optional because they won't always be used in our tests
    
    # We backtest the model on the last 20% of the flow series, with a horizon of 10 steps:
    backtest = model.historical_forecasts(series=flow, 
                                          past_covariates=past_covariates,
                                          future_covariates=future_covariates,
                                          start=0.8, 
                                          retrain=False,
                                          verbose=True, 
                                          forecast_horizon=10)
    
    flow[-len(backtest)-100:].plot()
    backtest.plot(label='backtest (n=10)')
    print('Backtest RMSE = {}'.format(rmse(flow, backtest)))


LENGTH = 3 * 365

my_covariate = (tg.sine_timeseries(length=LENGTH, 
                                   value_frequency=(1/14), 
                                   freq='D', 
                                   column_name='my_covariate')
             + 0.4 * tg.gaussian_timeseries(length=LENGTH, freq='D'))

melting = (tg.sine_timeseries(length=LENGTH, 
                              value_frequency=(1/365), 
                              freq='D', 
                              column_name='melting')
           + 0.15 * tg.gaussian_timeseries(length=LENGTH, freq='D'))

rainfalls = (tg.sine_timeseries(length=LENGTH, 
                                value_frequency=(1/14), 
                                freq='D', 
                                column_name='rainfall')
             + 0.3 * tg.gaussian_timeseries(length=LENGTH, freq='D'))

melting_contribution = 0.5 * melting.shift(5)

all_contributions = [melting_contribution] + [0.1 * rainfalls.shift(lag) for lag in range(5)]

flow = sum(
    [series[melting_contribution.start_time():][:melting.end_time()] 
     for series in all_contributions]
).with_columns_renamed('melting', 'flow')

brnn_melting_and_rain = BlockRNNModel(input_chunk_length=30, 
                                      output_chunk_length=10, 
                                      n_rnn_layers=2)
brnn_melting_and_rain.fit(flow, 
                          # past_covariates=melting.stack(rainfalls).stack(rainfalls), 
                          # past_covariates=[melting,rainfalls,my_covariate],
                          past_covariates=melting.stack(rainfalls).stack(my_covariate),
                          epochs=10, 
                          verbose=True)

flow_train, _ = flow.split_before(0.8)

eval_model(brnn_melting_and_rain, 
           #past_covariates=melting.stack(rainfalls)
           past_covariates=melting.stack(rainfalls).stack(my_covariate)
          )

The main thing was to stack the time series with melting.stack(rainfalls).stack(my_covariate) and then passing it also to the eval_model method.

Memristor
  • 599
  • 4
  • 11
0

This should fix the issue and allow you to fit the model using the covariate time series.

from darts.models import BlockRNNModel

my_covariate = (tg.sine_timeseries(length=LENGTH, 
                                value_frequency=(1/14), 
                                freq='D', 
                                column_name='my_covariate')
             + 0.4 * tg.gaussian_timeseries(length=LENGTH, freq='D'))

# Trim all the time series so they are the same length
flow_train = flow_train.trim()
melting = melting.trim()
rainfalls = rainfalls.trim()
my_covariate = my_covariate.trim()

brnn_melting_and_rain = BlockRNNModel(input_chunk_length=30, 
                                      output_chunk_length=10, 
                                      n_rnn_layers=2)

brnn_melting_and_rain.fit(flow_train, 
                          past_covariates=[melting,rainfalls,my_covariate],
                          epochs=10, 
                          verbose=True)

eval_model(brnn_melting_and_rain, 
           past_covariates=melting.stack(rainfalls))