Time series forest - interval-based classification.

Classes

TimeSeriesForestClassifier

class algorithms.timeseries.classification.interval.TimeSeriesForestClassifier(TimeSeriesClassifier)

Classification from summary statistics of random intervals.

Some series are distinguished not by a local motif or an overall shape, but by what happens in a particular stretch of time — a device that draws more current during startup, a patient whose reading trends upward only in the third hour. The time series forest draws random intervals, describes each by three cheap statistics, and lets a forest decide which stretches matter.

Because a tree can split on "the slope between t=40 and t=90", the fitted model localises where in time the difference lives, which none of the other members of this family does.

Constructor
__init__(
    self,
    n_intervals: Any = 'sqrt',
    min_interval: int = 3,
    n_estimators: int = 200,
    estimator: Optional[Any] = None,
    random_state: Optional[int] = None,
)

Overview

  1. Draw n_intervals random intervals of random position and width.
  2. Describe each by its mean, standard deviation and
least-squares slope against time.
  1. Concatenate into a feature vector of 3 * n_intervals values.
  2. Fit a random forest on those features.

Theory

For an interval [a, b) the three features are

\mu = \frac{1}{w} \sum_{t=a}^{b-1} x_t, \quad \sigma = \sqrt{\frac{1}{w} \sum_{t=a}^{b-1} (x_t - \mu)^2}, \quad \beta = \frac{\mathrm{Cov}(t, x)}{\mathrm{Var}(t)}

with w = b - a. Mean captures level, standard deviation captures activity, slope captures trend — between them a coarse but surprisingly effective description of a stretch of series.

The three are computed from prefix sums of x, x^2 and tx, so an interval costs O(1) whatever its width; because time is a run of consecutive integers, \mathrm{Var}(t) is the closed form (w^2 - 1)/12 and needs no accumulation at all.

Parameters

n_intervals
int or str = 'sqrt'
Number of random intervals. 'sqrt' uses :math:`\lceil \sqrt{L} \rceil`, the classical choice.
min_interval
int = 3
Shortest interval. Below three points the slope is meaningless.
n_estimators
int = 200
Trees in the forest.
estimator
Classifier
Head fitted on the interval features. Defaults to RandomForestClassifier.
random_state
int
Seed for interval sampling and the forest.

Attributes

intervals_
np.ndarray of shape (n_intervals, 2)
Fitted interval bounds, as [start, end) rows.
estimator_
Classifier
The fitted head.
classes_
np.ndarray of shape (n_classes,)
Class labels seen during fit.

Notes

Complexity. Feature extraction is O(n L) to build the prefix sums plus O(n k) for k intervals — the interval count does not multiply the series length. It runs in the shared C++ kernel tuiml._cpp_ext.timeseries.interval_features. The forest then dominates.

When to use. Reach for this when the discriminating information is localised in time and the series are aligned — the same phase of the same process across instances. It is the wrong choice when patterns drift in position, since an interval is fixed: there ShapeletTransformClassifier or BOSSClassifier search over positions instead. Like every member of the family it is beaten on raw accuracy by MiniRocketClassifier more often than not; its value here is a distinct, cheap, temporally localised view.

Multivariate panels are handled by extracting the same intervals from every channel and concatenating.

References

Deng2013
Deng, H., Runger, G., Tuv, E., & Vladimir, M. (2013). A Time Series Forest for Classification and Feature Extraction. Information Sciences, 239, 142-153. :doi:`10.1016/j.ins.2013.02.030`
Middlehurst2020
Middlehurst, M., Large, J., & Bagnall, A. (2020). The Canonical Interval Forest (CIF) Classifier for Time Series Classification. IEEE Big Data, 188-195. :doi:`10.1109/BigData50022.2020.9378424`
python
>>> import numpy as np
>>> from tuiml.algorithms.timeseries.classification import TimeSeriesForestClassifier
>>> rng = np.random.default_rng(0)
>>> # The classes differ only in the middle third of the series.
>>> X = rng.normal(0, 1.0, (80, 90))
>>> y = np.arange(80) % 2
>>> X[y == 1, 30:60] += np.linspace(0, 4, 30)
>>> model = TimeSeriesForestClassifier(n_estimators=100, random_state=0).fit(X, y)
>>> float((model.predict(X) == y).mean())
1.0

Methods

get_parameter_schema (cls) -> Dict[str, Dict[str, Any]]

Return JSON Schema for algorithm parameters.

get_capabilities (cls) -> List[str]

Return supported capabilities.

get_complexity (cls) -> str

Return complexity analysis.

get_references (cls) -> List[str]

Return academic citations.

fit (self, X: np.ndarray, y: np.ndarray) -> 'TimeSeriesForestClassifier'

Draw intervals and fit the forest on their statistics.

Parameters
X
np.ndarray of shape (n_samples, n_timepoints) or (n_samples, n_channels, n_timepoints)
Training series.
y
np.ndarray of shape (n_samples,)
Training labels.
Returns
self
TimeSeriesForestClassifier
The fitted classifier.
transform (self, X: np.ndarray) -> np.ndarray

Return the interval statistics of a panel.

Parameters
X
np.ndarray of shape (n_samples, n_timepoints) or (n_samples, n_channels, n_timepoints)
Series to transform.
Returns
features
np.ndarray of shape (n_samples, 3 * n_intervals * n_channels)
Mean, standard deviation and slope per interval per channel.
predict (self, X: np.ndarray) -> np.ndarray

Classify each series.

Parameters
X
np.ndarray of shape (n_samples, n_timepoints) or (n_samples, n_channels, n_timepoints)
Series to classify.
Returns
y_pred
np.ndarray of shape (n_samples,)
Predicted labels.
predict_proba (self, X: np.ndarray) -> np.ndarray

Return class probabilities from the forest.

Parameters
X
np.ndarray of shape (n_samples, n_timepoints) or (n_samples, n_channels, n_timepoints)
Series to classify.
Returns
proba
np.ndarray of shape (n_samples, n_classes)
Class probabilities.
__repr__ (self) -> str

Return a readable representation of the classifier.