DummyDriftDetector¶
Baseline drift detector that generates 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
Type → str
Default →
fixed
The trigger method to use.
*fixed
*random
-
t_0
Type → int
Default →
300
Reference point to define triggers.
-
w
Type → int
Default →
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
Type → bool
Default →
False
Whether to change the
seed
andw
values each timeclone()
is called. -
seed
Type → int | None
Default →
None
Random seed for reproducibility.
Attributes¶
-
drift_detected
Whether or not a drift is detected following the last update.
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 = DummyDriftDetector(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 = DummyDriftDetector(
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:
DummyDriftDetector(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 detector with a single data point.
Parameters
- x — 'int | float'
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.
-
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. ↩