forecast and predictor

This commit is contained in:
Dr. Kashif Rasul
2019-12-06 16:38:16 +01:00
parent be3301f40b
commit 7baca9339f
5 changed files with 118 additions and 74 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
from .common import DataEntry, FieldName, Dataset
from .list_dataset import ListDataset
from .loader import TrainDataLoader
from .loader import TrainDataLoader, InferenceDataLoader
from .sampler import (
InstanceSampler,
BucketInstanceSampler,
+1 -1
View File
@@ -1,5 +1,5 @@
from .estimator import Estimator, PTSEstimator
from .forecast import Forecast
from .forecast import Forecast, SampleForecast, QuantileForecast
from .predictor import Predictor
from .quantile import Quantile
from .utils import get_module_forward_input_names, copy_parameters
+71 -72
View File
@@ -322,84 +322,83 @@ class QuantileForecast(Forecast):
)
# class DistributionForecast(Forecast):
# """
# A `Forecast` object that uses a distribution directly.
# This can for instance be used to represent marginal probability
# distributions for each time point -- although joint distributions are
# also possible, e.g. when using MultiVariateGaussian).
class DistributionForecast(Forecast):
"""
A `Forecast` object that uses a distribution directly.
This can for instance be used to represent marginal probability
distributions for each time point -- although joint distributions are
also possible, e.g. when using MultiVariateGaussian).
# Parameters
# ----------
# distribution
# Distribution object. This should represent the entire prediction
# length, i.e., if we draw `num_samples` samples from the distribution,
# the sample shape should be
Parameters
----------
distribution
Distribution object. This should represent the entire prediction
length, i.e., if we draw `num_samples` samples from the distribution,
the sample shape should be
# samples = trans_dist.sample(num_samples)
# samples.shape -> (num_samples, prediction_length)
samples = trans_dist.sample(num_samples)
samples.shape -> (num_samples, prediction_length)
# start_date
# start of the forecast
# freq
# forecast frequency
# info
# additional information that the forecaster may provide e.g. estimated
# parameters, number of iterations ran etc.
# """
# @validated()
# def __init__(
# self,
# distribution: Distribution,
# start_date,
# freq,
# item_id: Optional[str] = None,
# info: Optional[Dict] = None,
# ):
# self.distribution = distribution
# self.shape = (self.distribution.batch_shape +
# self.distribution.event_shape)
# self.prediction_length = self.shape[0]
# self.item_id = item_id
# self.info = info
start_date
start of the forecast
freq
forecast frequency
info
additional information that the forecaster may provide e.g. estimated
parameters, number of iterations ran etc.
"""
def __init__(
self,
distribution: Distribution,
start_date,
freq,
item_id: Optional[str] = None,
info: Optional[Dict] = None,
):
self.distribution = distribution
self.shape = (self.distribution.batch_shape +
self.distribution.event_shape)
self.prediction_length = self.shape[0]
self.item_id = item_id
self.info = info
# assert isinstance(
# start_date,
# pd.Timestamp), "start_date should be a pandas Timestamp object"
# self.start_date = start_date
assert isinstance(
start_date,
pd.Timestamp), "start_date should be a pandas Timestamp object"
self.start_date = start_date
# assert isinstance(freq, str), "freq should be a string"
# self.freq = freq
# self._mean = None
assert isinstance(freq, str), "freq should be a string"
self.freq = freq
self._mean = None
# @property
# def mean(self):
# """
# Forecast mean.
# """
# if self._mean is not None:
# return self._mean
# else:
# self._mean = self.distribution.mean.asnumpy()
# return self._mean
@property
def mean(self):
"""
Forecast mean.
"""
if self._mean is not None:
return self._mean
else:
self._mean = self.distribution.mean.asnumpy()
return self._mean
# @property
# def mean_ts(self):
# """
# Forecast mean, as a pandas.Series object.
# """
# return pd.Series(self.index, self.mean)
@property
def mean_ts(self):
"""
Forecast mean, as a pandas.Series object.
"""
return pd.Series(self.index, self.mean)
# def quantile(self, level):
# level = Quantile.parse(level).value
# q = self.distribution.quantile(mx.nd.array([level])).asnumpy()[0]
# return q
def quantile(self, level):
level = Quantile.parse(level).value
q = self.distribution.quantile(mx.nd.array([level])).asnumpy()[0]
return q
# def to_sample_forecast(self, num_samples: int = 200) -> SampleForecast:
# return SampleForecast(
# samples=self.distribution.sample(num_samples),
# start_date=self.start_date,
# freq=self.freq,
# item_id=self.item_id,
# info=self.info,
# )
def to_sample_forecast(self, num_samples: int = 200) -> SampleForecast:
return SampleForecast(
samples=self.distribution.sample(num_samples),
start_date=self.start_date,
freq=self.freq,
item_id=self.item_id,
info=self.info,
)
+43
View File
@@ -0,0 +1,43 @@
from abc import ABC, abstractmethod
from typing import Any, Callable, Iterator, List, Optional
import numpy as np
import torch
import torch.nn as nn
from pts.dataset import InferenceDataLoader, DataEntry
from pts.model import Forecast, DistributionForecast
from pts.modules import DistributionOutput
OutputTransform = Callable[[DataEntry, np.ndarray], np.ndarray]
class ForecastGenerator(ABC):
"""
Classes used to bring the output of a network into a class.
"""
@abstractmethod
def __call__(self,
inference_data_loader: InferenceDataLoader,
prediction_net: nn.Module,
input_names: List[str],
freq: str,
output_transform: Optional[OutputTransform],
num_samples: Optional[int],
**kwargs) -> Iterator[Forecast]:
pass
class DistributionForecastGenerator(ForecastGenerator):
def __init__(self, distr_output: DistributionOutput) -> None:
self.distr_output = distr_output
def __call__(self,
inference_data_loader: InferenceDataLoader,
prediction_net: nn.Module,
input_names: List[str],
freq: str,
output_transform: Optional[OutputTransform],
num_samples: Optional[int],
**kwargs) -> Iterator[DistributionForecast]:
+2
View File
@@ -20,3 +20,5 @@ class Predictor(ABC):
class PTSPredictor(Predictor):
BlockType = nn.Module