Skip to content

Commit

Permalink
ENH: Add ability to append to a model
Browse files Browse the repository at this point in the history
  • Loading branch information
bashtage committed Jul 12, 2023
1 parent 98a2bfa commit 93e294c
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 2 deletions.
24 changes: 23 additions & 1 deletion arch/univariate/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
)
from arch.univariate.distribution import Distribution, Normal
from arch.univariate.volatility import ConstantVariance, VolatilityProcess
from arch.utility.array import ensure1d
from arch.utility.array import ensure1d, append_same_type
from arch.utility.exceptions import (
ConvergenceWarning,
DataScaleWarning,
Expand Down Expand Up @@ -230,6 +230,28 @@ def name(self) -> str:
"""The name of the model."""
return self._name

def append(self, y: ArrayLike) -> None:
"""
Append data to the model
Parameters
----------
y : ndarray or Series
Data to append
Returns
-------
ARCHModel
Model with data appended
"""
_y = ensure1d(y, "y", series=True)
self._y_original = append_same_type(self._y_original, y)
self._y_series = pd.concat([self._y_series, _y])
self._y = np.concatenate([self._y, np.asarray(_y)])

self._fit_indices: [0, int(self._y.shape[0])]
self._fit_y = self._y

def constraints(self) -> tuple[Float64Array, Float64Array]:
"""
Construct linear constraint arrays for use in non-linear optimization
Expand Down
21 changes: 21 additions & 0 deletions arch/univariate/mean.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
SkewStudent,
StudentsT,
)
from arch.utility.array import append_same_type

if TYPE_CHECKING:
# Fake path to satisfy mypy
Expand Down Expand Up @@ -269,6 +270,7 @@ def __init__(
distribution=distribution,
rescale=rescale,
)
self._x_original = x
self._x = x
self._x_names: list[str] = []
self._x_index: None | NDArray | pd.Index = None
Expand Down Expand Up @@ -307,6 +309,25 @@ def __init__(

self._init_model()

def append(self, y: ArrayLike, x: ArrayLike2D | None = None) -> None:
super().append(y)
if x is not None:
if self._x is None:
raise ValueError("x was not provided in the original model")
_x = np.atleast_2d(np.asarray(x))
if _x.ndim != 2:
raise ValueError("x must be 2-d")
elif _x.shape[1] != self._x.shape[1]:
raise ValueError(
"x must have the same number of columns as the original x"
)
self._x_original = append_same_type(self._x_original, x)
self._x = np.asarray(self._x_original)
if self._x.shape[0] != self._y.shape[0]:
raise ValueError("x must have the same number of observations as y")

self._init_model()

def _scale_changed(self):
"""
Called when the scale has changed. This allows the model
Expand Down
31 changes: 30 additions & 1 deletion arch/utility/array.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,16 @@
from typing import Any, Literal, overload

import numpy as np
from pandas import DataFrame, DatetimeIndex, Index, NaT, Series, Timestamp, to_datetime
from pandas import (
DataFrame,
DatetimeIndex,
Index,
NaT,
Series,
Timestamp,
to_datetime,
concat,
)

from arch.typing import AnyPandas, ArrayLike, DateLike, NDArray

Expand Down Expand Up @@ -310,3 +319,23 @@ def find_index(s: AnyPandas, index: int | DateLike) -> int:
if loc.size == 0:
raise ValueError("index not found")
return int(loc)


def append_same_type(original, new):
if not isinstance(new, type(original)):
raise TypeError(
"Input data must be the same type as the original data. "
f"Got {type(new)}, expected {type(original)}."
)
if isinstance(original, (Series, DataFrame)):
extended = concat([original, new], axis=0)
elif isinstance(original, np.ndarray):
extended = np.concatenate([original, new])
elif isinstance(original, list):
extended = original + new
else:
raise TypeError(
"Input data must be a pandas Series, DataFrame, numpy ndarray, or "
f"list. Got {type(original)}."
)
return extended

0 comments on commit 93e294c

Please sign in to comment.