Skip to content

Forecasting API

Forecasters learn one series with learn_one(y) and forecast it with forecast_one(). Regressors learn a target from covariates with learn_one(x, y) and predict it with predict_one(x). Both issue a Forecast.

SeasonalNaive

Python
SeasonalNaive(season_length: int = 1, *, horizon: int = 1, residual_alpha: float = 0.05, min_scale: float = 1e-06)

Bases: BaseForecaster

Forecast each lead with the value one cycle earlier.

Lead h repeats the value at the same position of the last observed cycle. With season_length=1 this is the naive forecast: every lead repeats the last value. It is the usual baseline a forecaster must beat.

Parameters:

Name Type Description Default
season_length int

Observations per cycle; 1 for the naive forecast.

1
horizon int

Largest lead to forecast.

1
residual_alpha float

Weight of each new absolute error in the faded mean absolute error kept for every lead, in (0, 1].

0.05
min_scale float

Positive floor for the reported spread, in target units.

1e-06
Notes

Two cycles warm the forecaster up. The spread of every lead starts at the mean absolute seasonal-naive error within the second cycle, then each lead fades towards its own errors. State is O(season_length + horizon^2) and each event after warm-up costs O(horizon).

Examples:

Python
from aberrant.forecast import SeasonalNaive

model = SeasonalNaive(season_length=3, horizon=2)
for y in [1.0, 5.0, 3.0, 1.5, 5.5, 3.5]:
    model.learn_one(y)
model.forecast_one().mean  # (1.5, 5.5)

is_ready property

Python
is_ready: bool

Whether two complete cycles have been learned.

reset

Python
reset() -> None

Forget every learned value and error.

learn_one

Python
learn_one(y: float) -> None

Learn the next value of the series.

forecast_one

Python
forecast_one() -> Forecast | None

Forecast leads 1..horizon, or None before two cycles.

HoltWinters

Python
HoltWinters(season_length: int, *, horizon: int = 1, alpha: float = 0.2, beta: float = 0.05, gamma: float = 0.1, residual_alpha: float = 0.05, min_scale: float = 1e-06)

Bases: BaseForecaster

Forecast level, trend and one season with additive Holt-Winters.

Lead h forecasts level + h * trend + season at the matching seasonal position. Every learned value advances one seasonal position.

Parameters:

Name Type Description Default
season_length int

Known number of observations in a cycle, at least two.

required
horizon int

Largest lead to forecast.

1
alpha float

Level smoothing weight in [0, 1].

0.2
beta float

Trend smoothing weight in [0, 1] (the usual beta-star parameter).

0.05
gamma float

Seasonal smoothing weight in [0, 1-alpha], using prior level and trend in the seasonal update.

0.1
residual_alpha float

Weight of each new absolute error in the faded mean absolute error kept for every lead, in (0, 1].

0.05
min_scale float

Positive floor for the reported spread, in target units.

1e-06
Notes

Two cycles initialize the model as in :class:~aberrant.model.timeseries.SeasonalResidualDetector, whose scores equal this forecaster's lead-1 residual divided by its lead-1 spread. Every lead's spread starts at the mean absolute error of the fitted warm-up model, then fades towards that lead's own errors. State is O(season_length + horizon^2) and each event costs O(horizon). Unrepresentable arithmetic raises OverflowError without changing state.

References

Hyndman and Athanasopoulos, Forecasting: Principles and Practice, 3rd ed., additive Holt-Winters component equations: https://otexts.com/fpp3/holt-winters.html

is_ready property

Python
is_ready: bool

Whether two complete cycles have been learned.

reset

Python
reset() -> None

Forget learned components and errors.

learn_one

Python
learn_one(y: float) -> None

Learn the next value of the series.

forecast_one

Python
forecast_one() -> Forecast | None

Forecast leads 1..horizon, or None before two cycles.

RLSRegressor

Python
RLSRegressor(*, forgetting: float = 0.999, delta: float = 1000.0, fit_intercept: bool = True, residual_alpha: float = 0.05, min_scale: float = 1e-06)

Bases: BaseRegressor

Predict a target linearly from covariates, by recursive least squares.

Each event updates the weights exactly as a least-squares refit with geometrically faded event weights would, at O(d^2) cost for d coefficients. The covariate names are fixed by the first learned event.

Parameters:

Name Type Description Default
forgetting float

Weight factor in (0, 1] applied to past events at every update. 1 weighs all events equally; 0.999 remembers roughly the last 1,000.

0.999
delta float

Positive initial variance of the coefficients. Larger values mean a weaker prior towards zero.

1000.0
fit_intercept bool

Whether to learn a constant term.

True
residual_alpha float

Weight of each new absolute error in the faded mean absolute error that gives the spread, in (0, 1].

0.05
min_scale float

Positive floor for the reported spread, in target units.

1e-06
Notes

Once d events are learned, each further event's error is measured against the prediction made before learning it, and the faded mean absolute error of those errors is the reported spread. The model is ready after the first such error, at d + 1 events. With forgetting < 1 and covariates that stop varying, the coefficient covariance can grow without bound; keep inputs informative or use 1. Unrepresentable arithmetic raises OverflowError without changing state.

Examples:

Python
from aberrant.forecast import RLSRegressor

model = RLSRegressor()
for a, b in [(0.0, 1.0), (1.0, 0.0), (1.0, 1.0), (2.0, 1.0)]:
    x = {"a": a, "b": b}
    prediction = model.predict_one(x)  # None until ready
    model.learn_one(x, 2.0 * a - b + 1.0)
model.predict_one({"a": 3.0, "b": 2.0}).mean  # close to (5.0,)
References

Haykin, Adaptive Filter Theory, 5th ed., chapter 10 (recursive least-squares adaptive filters).

is_ready property

Python
is_ready: bool

Whether a spread has been measured, after d + 1 events.

feature_names property

Python
feature_names: tuple[str, ...] | None

Covariate names in coefficient order, once learned.

coefficients property

Python
coefficients: dict[str, float]

Learned weight per covariate, and "intercept" when fitted.

reset

Python
reset() -> None

Forget coefficients, covariate names and the spread.

predict_one

Python
predict_one(x: FeatureMap) -> Forecast | None

Predict the target of the event with covariates x at lead 0.

learn_one

Python
learn_one(x: FeatureMap, y: float) -> None

Learn the target y of the event with covariates x.

ResidualDetector

Python
ResidualDetector(model: ForecasterProtocol | RegressorProtocol, target: str, *, lead: int | None = None, score: Literal['absolute', 'scaled'] = 'scaled')

Score each event by how far its target misses a forecast or prediction.

The detector splits each event into the target x[target] and, for a regressor, the covariates (every other key). It scores before learning:

  • A regressor predicts the target from the event's covariates (lead 0).
  • A forecaster's score uses the forecast issued lead events earlier, so the target is compared with what was expected before it arrived. A forecaster learns only the target; other keys are ignored.

Parameters:

Name Type Description Default
model ForecasterProtocol | RegressorProtocol

An online forecaster (forecast_one()) or regressor (predict_one(x)).

required
target str

Name of the target feature in every event.

required
lead int | None

Forecast lead to score, from 1 to the forecaster's horizon; defaults to 1. Must be 0, the default, for a regressor.

None
score Literal['absolute', 'scaled']

"scaled" divides the absolute residual by the forecast's spread at that lead; "absolute" keeps target units.

'scaled'
Notes

Scores are non-negative and higher is more anomalous. They are 0 until a forecast for the event exists. The detector learns every event, so the model adapts to anomalies too; a longer lead compares with a forecast issued before an anomaly began. Calibrate the scores, for example with :class:~aberrant.calibration.ScoreCalibrator.

Examples:

Python
from aberrant.forecast import HoltWinters, ResidualDetector

detector = ResidualDetector(HoltWinters(season_length=24), "load")
for x in stream:
    score = detector.score_one(x)
    detector.learn_one(x)

forecast_for

Python
forecast_for(x: FeatureMap) -> Forecast | None

Return the forecast x is scored against, or None without one.

For a forecaster it is the forecast issued lead events earlier; read it at lead. For a regressor it is the prediction from the covariates of x. The target is not read, so x may be the event before its target is known.

explain_one

Python
explain_one(x: FeatureMap) -> tuple[float, float | None, float | None]

Return (score, expected target, signed residual) without learning.

Before a forecast exists return (0.0, None, None). A positive residual means the target exceeds what was expected.

score_one

Python
score_one(x: FeatureMap) -> float

Return the nonconformity of x[target], or 0 without a forecast.

learn_one

Python
learn_one(x: FeatureMap) -> None

Learn the event, then keep the forecaster's next forecast.

nonconformity

Python
nonconformity(forecast: Forecast, lead: int, y: float, score: NonconformityScore = 'absolute', *, alpha: float | None = None) -> float

How far y falls from the forecast at lead; larger is stranger.

  • absolute: |y - mean|, in target units.
  • scaled: |y - mean| / spread, comparable across leads and series.
  • cqr: max(lo - y, y - hi) for the quantiles at alpha / 2 and 1 - alpha / 2; negative inside that interval (conformalized quantile regression).

Feed the score to a calibrator with the target event as its key. Each lead is its own score stream, since forecast errors grow with the lead.

interval

Python
interval(forecast: Forecast, lead: int, threshold: float, score: NonconformityScore = 'absolute', *, alpha: float | None = None) -> tuple[float, float]

The values of y whose score stays at or below threshold.

An infinite threshold, as a calibrator issues before its first score, gives (-inf, inf). A cqr threshold below -(hi - lo) / 2 leaves no such value; the interval then collapses to the quantiles' midpoint.

BaseForecaster

Python
BaseForecaster(horizon: int)

Bases: ABC

An online forecaster of one series sampled at a fixed cadence.

forecast_one() forecasts leads 1..horizon from the values learned so far, and learn_one(y) learns the next value. Each learned value advances the series by one step: there are no timestamps, so resample irregular or missing readings before learning them.

is_ready abstractmethod property

Python
is_ready: bool

Whether forecast_one returns a forecast.

learn_one abstractmethod

Python
learn_one(y: float) -> None

Learn the next value of the series.

forecast_one abstractmethod

Python
forecast_one() -> Forecast | None

Forecast leads 1..horizon, or None before readiness.

reset abstractmethod

Python
reset() -> None

Forget everything learned.

BaseRegressor

Bases: ABC

An online regressor of one target from the covariates of each event.

predict_one(x) predicts the target of the event with covariates x at lead 0, and learn_one(x, y) learns that event's target once known.

is_ready abstractmethod property

Python
is_ready: bool

Whether predict_one returns a prediction.

learn_one abstractmethod

Python
learn_one(x: FeatureMap, y: float) -> None

Learn the target y of the event with covariates x.

predict_one abstractmethod

Python
predict_one(x: FeatureMap) -> Forecast | None

Predict the target at lead 0, or None before readiness.

reset abstractmethod

Python
reset() -> None

Forget everything learned.