Menelaus implements algorithms for drift detection in machine learning. Drift detection is a branch of machine learning focused on the detection of unforeseen shifts in data. The relationships between variables in a dataset are rarely static and can be affected by changes in both internal and external factors, e.g. changes in data collection techniques, external protocols, and/or population demographics. Both undetected changes in data and undetected model underperformance pose risks to the users thereof. The aim of this package is to enable monitoring of data and of model performance.
The algorithms contained within this package were identified through a comprehensive literature survey. Menelaus' aim was to implement drift detection algorithms that cover a range of statistical methodology. Of the algorithms identified, all are able to identify when drift is occurring; some can highlight suspicious regions of the data in which drift is more significant; and others can also provide model retraining recommendations.
Menelaus implements drift detectors for both streaming and batch data. In a streaming setting, data is arriving continuously and is processed one observation at a time. Streaming detectors process the data with each new observation that arrives and are intended for use cases in which instant analytical results are desired. In a batch setting, information is collected over a period of time. Once the predetermined set is "filled", data is fed into and processed by the drift detection algorithm as a single batch. Within a batch, there is no meaningful ordering of the data with respect to time. Batch algorithms are typically used when it is more important to process large volumes of information simultaneously, where the speed of results after receiving data is of less concern.
Menelaus is named for the Odyssean hero that defeated the shapeshifting Proteus.
Menelaus implements the following drift detectors.
Type | Detector | Abbreviation | Streaming | Batch |
---|---|---|---|---|
Change detection | Cumulative Sum Test | CUSUM | x | |
Change detection | Page-Hinkley | PH | x | |
Change detection | ADaptive WINdowing | ADWIN | x | |
Concept drift | Drift Detection Method | DDM | x | |
Concept drift | Early Drift Detection Method | EDDM | x | |
Concept drift | Linear Four Rates | LFR | x | |
Concept drift | Statistical Test of Equal Proportions to Detect concept drift | STEPD | x | |
Concept drift | Margin Density Drift Detection Method | MD3 | x | |
Data drift | Confidence Distribution Batch Detection | CDBD | x | |
Data drift | Hellinger Distance Drift Detection Method | HDDDM | x | |
Data drift | kdq-Tree Detection Method | kdq-Tree | x | x |
Data drift | PCA-Based Change Detection | PCA-CD | x | |
Data drift | Nearest Neighbor Density Variation Identification | NN-DVI | x | |
Ensemble | Streaming Ensemble | - | x | |
Ensemble | Batch Ensemble | - | x |
The three main types of detector are described below. More details, including references to the original papers, can be found in the respective module documentation on ReadTheDocs.
- Change detectors monitor single variables in the streaming context, and alarm when that variable starts taking on values outside of a pre-defined range.
- Concept drift detectors monitor the performance characteristics of a given model, trying to identify shifts in the joint distribution of the data's feature values and their labels. Note that change detectors can also be applied in this context.
- Data drift detectors monitor the distribution of the features; in that sense, they are model-agnostic. Such changes in distribution might be to single variables or to the joint distribution of all the features.
- Ensembles are groups of detectors, where each watches the same data, and drift is determined by combining their output. Menelaus implements a framework for wrapping detectors this way.
The detectors may be applied in two settings, as described in the Background section:
- Streaming, in which each new observation that arrives is processed separately, as it arrives.
- Batch, in which the data has no meaningful ordering with respect to time, and the goal is comparing two datasets as a whole.
Additionally, the library implements a kdq-Tree partitioner, for support of the kdq-Tree Detection Method. This data structure partitions a given feature space, then maintains a count of the number of samples from the given dataset that fall into each section of that partition. More details are given in the respective module.
Create a virtual environment as desired, then:
# for read-only, install from pypi:
pip install menelaus
# to allow editing, running tests, generating docs, etc.
# first, clone the git repo, then:
cd ./menelaus_clone_folder/
pip install -e .[dev]
# to run examples which use datasets from the wilds library,
# another install option is:
pip install menelaus[wilds]
Menelaus should work with Python 3.8 or higher.
Each detector implements the API defined by menelaus.detector
:
notably, they have an update
method which allows new data to be passed, and a drift_state
attribute which tells the user whether drift has been
detected, along with (usually) other attributes specific to the detector class.
Generally, the workflow for using a detector, given some data, is as follows:
from menelaus.concept_drift import ADWINAccuracy
from menelaus.data_drift import KdqTreeStreaming
from menelaus.datasets import fetch_rainfall_data
from menelaus.ensemble import StreamingEnsemble, SimpleMajorityElection
# has feature columns, and a binary response 'rain'
df = fetch_rainfall_data()
# use a concept drift detector (response-only)
detector = ADWINAccuracy()
for i, row in df.iterrows():
detector.update(X=None, y_true=row['rain'], y_pred=0)
assert detector.drift_state != "drift", f"Drift detected in row {i}"
# use data drift detector (features-only)
detector = KdqTreeStreaming(window_size=5)
for i, row in df.iterrows():
detector.update(X=df.loc[[i], df.columns != 'rain'], y_true=None, y_pred=None)
assert detector.drift_state != "drift", f"Drift detected in row {i}"
# use ensemble detector (detectors + voting function)
ensemble = StreamingEnsemble(
{
'a': ADWINAccuracy(),
'k': KdqTreeStreaming(window_size=5)
},
SimpleMajorityElection()
)
for i, row in df.iterrows():
ensemble.update(X=df.loc[[i], df.columns != 'rain'], y_true=row['rain'], y_pred=0)
assert ensemble.drift_state != "drift", f"Drift detected in row {i}"
As a concept drift detector, ADWIN requires both a true value (y_true
) and a
predicted value (y_predicted
) at each update step. The data drift detector
KdqTreeStreaming only requires the feature values at each step (X
). More
detailed examples, including code for visualizating drift locations, may be
found in the examples
directory, as stand-alone python scripts. The examples
along with output can also be viewed on the RTD website.
Install the library using the [dev]
option, as above.
-
Testing
Unit tests can be run with the command
pytest
. By default, a coverage report with highlighting will be generated inhtmlcov/index.html
. These default settings are specified insetup.cfg
under[tool:pytest]
. -
Documentation
HTML documentation can be generated at
menelaus/docs/build/html/index.html
with:cd docs/source sphinx-build . ../build
If the example notebooks for the docs need to be updated, the corresponding python scripts in the
examples
directory should also be regenerated via:cd docs/source/examples python convert_notebooks.py
Note that this will require the installation of
jupyter
andnbconvert
, which can be added to installation viapip install -e ".[dev, test]"
. -
Formatting:
This project uses
black
,bandit
, andflake8
for code formatting and linting, respectively. To satisfy these requirements when contributing, you may use them as the linter/formatter in your IDE, or manually run the following from the root directory:flake8 ./menelaus # linting bandit -r ./menelaus # security checks black ./menelaus # formatting
Authors: Leigh Nicholl, Thomas Schill, India Lindsay, Anmol Srivastava, Kodie P McNamara, Shashank Jarmale.
©2022 The MITRE Corporation. ALL RIGHTS RESERVED
Approved for Public Release; Distribution Unlimited. Public Release
Case Number 22-0244.