import abc
import logging
import weakref
from enum import Enum
from typing import (
Any,
Callable,
Dict,
List,
NamedTuple,
NewType,
Optional,
Tuple,
Union,
)
from weakref import ReferenceType
import numpy
import pandas
from sklearn.base import BaseEstimator, RegressorMixin
logger = logging.getLogger(__name__)
[docs]class ExtendedEnum(Enum):
[docs] @classmethod
def list(cls):
return list(map(lambda c: c.value, cls))
[docs] @classmethod
def names(cls):
return list(map(lambda c: c.name, cls))
[docs]class ModelT(str, ExtendedEnum):
prophet = "prophet"
holt_winters = "holt_winters"
auto_arima = "auto_arima"
sarimax = "sarimax"
[docs]class UnivariateModelT(str, ExtendedEnum):
arima = "arima"
auto_arima = "auto_arima"
prophet = "prophet"
holt_winters = "holt_winters"
sarimax = "sarimax"
Models = NewType("ModelT", ModelT)
[docs]class HierarchyVisualizerT(metaclass=abc.ABCMeta):
tree: "NAryTreeT"
[docs] def create_map(self):
...
[docs]class NAryTreeT(metaclass=abc.ABCMeta):
"""
Type definition of an NAryTree
"""
key: str
item: Union[pandas.Series, pandas.DataFrame]
exogenous: List[str] = None
children: List[Optional["NAryTreeT"]]
_parent: "Optional[ReferenceType[NAryTreeT]]"
visualizer: HierarchyVisualizerT
@property
def parent(self):
if self._parent:
return self._parent()
def __iter__(self) -> "NAryTreeT":
yield self
for child in self.children:
yield child
def __getstate__(self):
self._parent = None
return self.__dict__
def __setstate__(self, state):
self.__dict__ = state
for child in self.children:
child._parent = weakref.ref(self)
[docs] def num_nodes(self) -> int:
...
[docs] def is_leaf(self) -> bool:
...
[docs] def value_at_height(self, level: int) -> List:
...
[docs] def sum_at_height(self, level) -> int:
...
[docs] def get_height(self) -> int:
...
[docs] def level_order_traversal(self: "NAryTreeT") -> List[List[int]]:
...
[docs] def get_level_order_labels(self: "NAryTreeT") -> List[List[str]]:
...
[docs] def traversal_level(self) -> List["NAryTreeT"]:
...
[docs] def add_child(self, key=None, item=None, exogenous=None) -> "NAryTreeT":
...
[docs] def leaf_sum(self) -> int:
...
[docs] def to_pandas(self) -> pandas.DataFrame:
...
[docs] def get_node_height(self, key: str) -> int:
...
[docs] def get_series(self) -> pandas.Series:
...
[docs] def string_repr(self, prefix="", _last=True):
base = "".join([prefix, "- " if _last else "|- ", self.key, "\n"])
prefix += " " if _last else "| "
child_count = len(self.children)
for i, child in enumerate(self.children):
_last = i == (child_count - 1)
base += child.string_repr(_last=_last, prefix=prefix)
return base
def __repr__(self):
return self.string_repr()
__str__ = __repr__
[docs]class TimeSeriesModelT(BaseEstimator, RegressorMixin, metaclass=abc.ABCMeta):
""" Type definition of an TimeSeriesModel """
kind: str
node: NAryTreeT
model: Any
forecast: Optional[pandas.DataFrame]
residual: Optional[numpy.ndarray]
mse: Optional[numpy.ndarray]
transform: "TransformT"
@staticmethod
def _no_func(x):
return x
def _set_results_return_self(self, in_sample, y_hat) -> "TimeSeriesModelT":
...
[docs] def create_model(self, **kwargs):
...
[docs] def fit(self, **fit_args) -> "TimeSeriesModelT":
raise NotImplementedError
[docs] def predict(self, node: NAryTreeT, **predict_args):
raise NotImplementedError
[docs]class MethodT(ExtendedEnum):
OLS = "OLS"
WLSS = "WLSS"
WLSV = "WLSV"
FP = "FP"
PHA = "PHA"
AHP = "AHP"
BU = "BU"
NONE = "NONE"
# TODO: make this a proper recursive type when mypy supports it: https://github.com/python/mypy/issues/731
HierarchyT = Tuple[str, "HierarchyT"]
NodesT = ExogT = Dict[str, List[str]]
LowMemoryFitResultT = Tuple[str, str]
ModelFitResultT = Union[TimeSeriesModelT, LowMemoryFitResultT]
HTSFitResultT = List[ModelFitResultT]
TransformT = Union[Transform, bool]
ArrayLike = Union[numpy.ndarray, pandas.Series, pandas.DataFrame]