vignette("deriva") covers
signal_type = "error" methods (DDM and friends): they need
a labelled 0/1 (or continuous) error signal, usually built from a
model’s predictions with add_prediction_error().
signal_type = "distribution" methods are different: they
watch a raw numeric stream directly — no labels, no baseline error rate
— and flag a change in the stream’s distribution itself. This is the
right family when you want to monitor an input feature or a sensor
reading for drift, not just a model’s error.
sensor_monitoring, shipped with the package, is a
numeric sensor-reading stream: 500 stable observations centred at 0,
then 500 after the sensor drifted out of calibration and the mean
shifted to 2.
"kswin" (Kolmogorov-Smirnov Windowing) is a
signal_type = "distribution" method: it repeatedly compares
a recent window of the stream against an older one with a
Kolmogorov-Smirnov test.
KSWIN is stochastic — it draws a random sub-sample from its window at
every test. Pass seed to drift_detector() (or,
as here, straight into detect_drift(), which forwards it)
to get a result that is reproducible and does not depend on the state of
your session’s random number generator.
result <- detect_drift(sensor_monitoring, .col = value, method = "kswin", seed = 7)
subset(result, .drift)
#> # A tibble: 4 × 5
#> t value drift_true .warning .drift
#> <int> <dbl> <lgl> <lgl> <lgl>
#> 1 517 3.82 TRUE NA TRUE
#> 2 605 3.18 TRUE NA TRUE
#> 3 723 3.46 TRUE NA TRUE
#> 4 930 2.58 TRUE NA TRUENo detection fires in the 500 stable observations. Unlike DDM, which settles into a new stable state after one detection, KSWIN keeps comparing windows as they slide past the change point — so it fires several times while its window catches up to the new distribution, not just once. That is expected behaviour for a windowed method, not noise: every one of these detections comes after the true drift point, as the window repeatedly re-compares against the now-shifted data.
"adwin" (Adaptive Windowing) solves the same problem
with an adaptively-sized window instead of a fixed one, and is
deterministic — no seed needed:
detect_drift(sensor_monitoring, .col = value, method = "adwin") |>
subset(.drift)
#> # A tibble: 1 × 5
#> t value drift_true .warning .drift
#> <int> <dbl> <lgl> <lgl> <lgl>
#> 1 544 3.73 TRUE NA TRUEOn this stream ADWIN settles the way DDM did in
vignette("deriva"): a single detection, no repeated firing
while the window catches up. Which method fires once versus several
times is a property of the algorithm, not of one being more “correct”
than the other — see drift_detector("adwin") for its
hyperparameters, and vignette("deriva") for the full tidy
workflow
(fit()/advance()/augment()/…),
which works identically for distribution-based methods.