PeriodicTrigger¶
Generate pseudo drift detection signals.
There are two approaches1:
fixed
where the drift signal is generated everyt_0
samples. -random
corresponds to a pseudo-random drift detection strategy.
Parameters¶
-
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. - iftrigger_method="random"
,w
defines the probability bounds of triggering a drift. The chance of triggering a drift is \(0.5\) after observingt_0
instances and becomes \(1\) after monitoringt_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
andw
values each timeclone()
is called. -
seed (int) – defaults to
None
Random seed for reproducibility.
Attributes¶
-
drift_detected
Concept drift alarm. True if concept drift is detected.
Examples¶
>>> 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):
... _ = ptrigger.update(v)
... if ptrigger.drift_detected:
... 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):
... _ = rtrigger.update(v)
... if rtrigger.drift_detected:
... 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):
... _ = rtrigger.update(v)
... if rtrigger.drift_detected:
... print(f"Drift detected at instance {i}.")
Drift detected at instance 429.
Drift detected at instance 728.
Methods¶
update
Update the change detector with a single data point.
Parameters
- x (numbers.Number)
Returns
DriftDetector: self
Notes¶
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.
References¶
-
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. ↩