Skip to content


Generate pseudo drift detection signals.

There are two approaches1:

  • fixed where the drift signal is generated every t_0 samples. - random corresponds to a pseudo-random drift detection strategy.


  • trigger_method (str) – defaults to fixed

    The trigger method to use.
    * fixed
    * random

  • t_0 (int) – defaults to 300

    Reference point to define triggers.

  • w (int) – defaults to 0

    Auxiliary parameter whose purpose is twofold:
    - if trigger_method="fixed", the periodic drift signals will only start after an initial warm-up period randomly defined between [0, w]. Useful to avoid that all ensemble members are reset at the same time when periodic triggers are used as the adaptation strategy.
    - if trigger_method="random", w defines the probability bounds of triggering a drift. The chance of triggering a drift is \(0.5\) after observing t_0 instances and becomes \(1\) after monitoring t_0 + w / 2 instances. A sigmoid function is used to produce values between [0, 1] that are used as the reset probabilities.

  • dynamic_cloning (bool) – defaults to False

    Whether to change the seed and w values each time clone() is called.

  • seed (int) – defaults to None

    Random seed for reproducibility.


  • change_detected

    Concept drift alarm. True if concept drift is detected.

  • warning_detected

    Warning zone alarm. Indicates if the drift detector is in the warning zone. Applicability depends on each drift detector implementation. True if the change detector is in the warning zone.


>>> import random
>>> from river import drift

>>> rng = random.Random(42)

The observed values will not affect the periodic triggers.

>>> data = [rng.gauss(0, 1) for _ in range(1000)]

Let's start with the fixed drift signals:

>>> ptrigger = PeriodicTrigger(t_0=500, seed=42)
>>> for i, v in enumerate(data):
...     in_drift, _ = ptrigger.update(v)
...     if in_drift:
...         print(f"Drift detected at instance {i}.")
Drift detected at instance 499.
Drift detected at instance 999.

Now, the random drift signals:

>>> rtrigger = PeriodicTrigger(
...     trigger_method="random",
...     t_0=500,
...     w=100,
...     dynamic_cloning=True,
...     seed=42
... )
>>> for i, v in enumerate(data):
...     in_drift, _ = rtrigger.update(v)
...     if in_drift:
...         print(f"Drift detected at instance {i}.")
Drift detected at instance 368.
Drift detected at instance 817.

Remember to set a w > 0 value if random triggers are used:

>>> try:
...     PeriodicTrigger(trigger_method="random")
... except ValueError as ve:
...     print(ve)
The 'w' value must be greater than zero when 'trigger_method' is 'random'.

Since we set dynamic_cloning to True, a clone of the periodic trigger will have its internal paramenters changed:

>>> rtrigger = rtrigger.clone()
>>> for i, v in enumerate(data):
...     in_drift, _ = rtrigger.update(v)
...     if in_drift:
...         print(f"Drift detected at instance {i}.")
Drift detected at instance 429.
Drift detected at instance 728.



Return a fresh estimator with the same parameters.

The clone has the same parameters but has not been updated with any data. This works by looking at the parameters from the class signature. Each parameter is either - recursively cloned if it's a River classes. - deep-copied via copy.deepcopy if not. If the calling object is stochastic (i.e. it accepts a seed parameter) and has not been seeded, then the clone will not be idempotent. Indeed, this method's purpose if simply to return a new instance with the same input parameters.


Reset the change detector.


Update the change detector with a single data point.


  • value (numbers.Number)


typing.Tuple[bool, bool]: A tuple (drift, warning) where its elements indicate if a drift or a warning is detected.


When used in ensembles, a naive implementation of periodic drift signals would make all ensemble members reset at the same time. To avoid that, the dynamic_cloning parameter can be set to True. In this case, every time the clone method of this detector is called in an ensemble a new seed is defined. If dynamic_cloning=True and trigger_method="fixed", a new w between [0, t_0] will also be created for the new cloned instance.


  1. Heitor Gomes, Jacob Montiel, Saulo Martiello Mastelini, Bernhard Pfahringer, and Albert Bifet. On Ensemble Techniques for Data Stream Regression. IJCNN'20. International Joint Conference on Neural Networks. 2020.