Экспорт нескольких прогнозов GluonTS на pandas данные - PullRequest
0 голосов
/ 24 апреля 2020

У меня есть несколько временных рядов, которые я хотел бы спрогнозировать с помощью GluonTS , затем объединить, чтобы мой результат представлял собой pandas кадр данных с заголовками столбцов date, y (цель) , series (номер серии).

Проблема в том, что GluonTS производит генератор. Я могу посмотреть на каждую серию с next(iter(forecast_id)), но я хотел бы объединить все прогнозы, чтобы упростить экспорт в формате CSV.

Как я могу объединить прогнозы из всех серий в один pandas кадр данных?

import pandas as pd 
import numpy as np 
import mxnet as mx
from mxnet import gluon
from gluonts.dataset import common
from gluonts.model.baseline import SeasonalNaivePredictor
from gluonts.trainer import Trainer
from gluonts.evaluation.backtest import make_evaluation_predictions
from gluonts.dataset.util import to_pandas

N = 10  # number of time series
T = 100  # number of timesteps
prediction_length = 24
custom_dataset = np.random.normal(size=(N, T))
start = pd.Timestamp("01-01-2019", freq='1H') 

# train dataset: cut the last window of length "prediction_length", add "target" and "start" fields
train_ds = [{'target': x, 'start': start} for x in custom_dataset[:, :-prediction_length]]
# test dataset: use the whole dataset, add "target" and "start" fields
test_ds = [{'target': x, 'start': start} for x in custom_dataset]

predictor = SeasonalNaivePredictor(
    prediction_length=prediction_length,
    season_length=24,
    freq='1H'
)

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
)

test_entry = next(iter(forecast_it))
print(test_entry)
> gluonts.model.forecast.SampleForecast(freq="1H", info=None, item_id=None, samples=numpy.array([[-1.078548550605774, 0.3002452254295349, 0.1025903970003128, -1.6613410711288452, -0.2776057720184326, -0.020864564925432205, -1.9355241060256958, 1.0598571300506592, 0.16316552460193634, -0.9441472887992859, 2.7307169437408447, -0.35861697793006897, 0.22022956609725952, 0.8052476048469543, -1.1194337606430054, 0.05703512206673622, -1.1357367038726807, -2.544445037841797, 1.2661969661712646, 0.17130693793296814, 0.8647393584251404, -1.9620181322097778, -0.5465423464775085, 0.26572829484939575]], numpy.dtype("float32")), start_date=pandas.Timestamp("2019-01-04 04:00:00", freq="H"))

1 Ответ

1 голос
/ 25 апреля 2020

Вы можете распаковать запись следующим образом:

def sample_df(forecast):
    samples = forecast.samples
    ns, h = samples.shape
    dates = pd.date_range(forecast.start_date, freq=forecast.freq, periods=h)
    return pd.DataFrame(samples.T, index=dates)

Это просто захват различных свойств из SampleForecast.

Это начинается с прогноза samples, ndarray со строкой для выборки и столбцом для периода времени. Число столбцов дает горизонт прогнозирования h, который со свойствами start_date и freq можно присвоить pd.date_range для построения прогноза dates.

А затем samples транспонируются, давая строку за период времени и столбец для каждой выборки. Это может быть проиндексировано с восстановленным dates, и вы все настроены на один образец.

sample_df(test_entry)
#                             0
# 2019-01-04 04:00:00  0.748107
# 2019-01-04 05:00:00  1.620660
# 2019-01-04 06:00:00 -0.648520
# 2019-01-04 07:00:00  0.277669
# 2019-01-04 08:00:00 -1.010820
# ...

Чтобы обработать все ваши результаты, вы можете запустить этот метод независимо для каждого DataFrame и поместить все они вместе с pd.concat .

parts = [sample_df(entry).assign(entry=i)
         for i, entry in enumerate(forecast_it)]
pd.concat(parts)
#                             0  entry
# 2019-01-04 04:00:00  0.748107      0
# 2019-01-04 05:00:00  1.620660      0
# 2019-01-04 06:00:00 -0.648520      0
# 2019-01-04 07:00:00  0.277669      0
# 2019-01-04 08:00:00 -1.010820      0
# ...                       ...    ...
# 2019-01-04 23:00:00  0.999718      9
# 2019-01-05 00:00:00  0.027250      9
# 2019-01-05 01:00:00  2.030961      9
# 2019-01-05 02:00:00 -1.414711      9
# 2019-01-05 03:00:00  0.737124      9

Это также помечает каждый DataFrame знаком entry, чтобы отметить, из какого результата прогноза он получен.

Вы также можете использовать pd.DataFrame.melt для преобразования из одного столбца для образца в длинную форму со столбцом для идентификации образца. Некоторые переименования в конце могут сделать все довольно красиво для последующего анализа.

long_form = pd.concat(parts).reset_index().melt(['index', 'entry'])
long_form.rename(columns={
    'index': 'ts',
    'variable': 'sample',
    'value': 'forecast',
})
#                      ts  entry sample     value
# 0   2019-01-04 04:00:00      0      0  0.748107
# 1   2019-01-04 05:00:00      0      0  1.620660
# 2   2019-01-04 06:00:00      0      0 -0.648520
# 3   2019-01-04 07:00:00      0      0  0.277669
# 4   2019-01-04 08:00:00      0      0 -1.010820
# ..                  ...    ...    ...       ...
# 235 2019-01-04 23:00:00      9      0  0.999718
# 236 2019-01-05 00:00:00      9      0  0.027250
# 237 2019-01-05 01:00:00      9      0  2.030961
# 238 2019-01-05 02:00:00      9      0 -1.414711
# 239 2019-01-05 03:00:00      9      0  0.737124

Примечание: Этот код должен работать для любого количества образцов, давая столбец для каждого (или строки в длинной форме). Но результаты здесь имеют только один образец. Что дает?

Я прочитал соответствующий код, и базовый класс PresentablePredictor сгенерирует только один образец, независимо от того, что вы запрашиваете у make_evaluation_predictions. Параметр просто никогда не передается. Этот базовый класс используется для методологий не-глюонного прогнозирования, поэтому я предполагаю, что они просто ожидают, что они не будут случайными и пригодны только для генерации одного примера. Или это ошибка.

...