From 151a9bd1643c0dbca74ee96c6f1b0ad6aa8e6862 Mon Sep 17 00:00:00 2001 From: detlefarend Date: Wed, 12 Feb 2025 16:07:20 +0100 Subject: [PATCH] Refact: Separation of anomaly detection from drift detection #1133 --- .../anomalydetectors/anomalies/__init__.py | 1 - .../anomalydetectors/anomalies/basics.py | 4 +- .../anomalies/clusterbased/drift.py | 39 --- .../tasks/anomalydetectors/anomalies/drift.py | 34 --- .../streams/tasks/driftdetectors/__init__.py | 1 + .../oa/streams/tasks/driftdetectors/basics.py | 235 ++++++++++++++++++ .../driftdetectors/clusterbased/__init__.py | 1 + .../driftdetectors/clusterbased/basics.py | 83 +++++++ .../clusterbased}/drift_detector.py | 13 +- .../tasks/driftdetectors/drifts/__init__.py | 2 + .../tasks/driftdetectors/drifts/basics.py | 62 +++++ .../drifts/clusterbased/__init__.py | 1 + .../drifts/clusterbased/basics.py | 126 ++++++++++ 13 files changed, 521 insertions(+), 81 deletions(-) delete mode 100644 src/mlpro/oa/streams/tasks/anomalydetectors/anomalies/clusterbased/drift.py delete mode 100644 src/mlpro/oa/streams/tasks/anomalydetectors/anomalies/drift.py create mode 100644 src/mlpro/oa/streams/tasks/driftdetectors/__init__.py create mode 100644 src/mlpro/oa/streams/tasks/driftdetectors/basics.py create mode 100644 src/mlpro/oa/streams/tasks/driftdetectors/clusterbased/__init__.py create mode 100644 src/mlpro/oa/streams/tasks/driftdetectors/clusterbased/basics.py rename src/mlpro/oa/streams/tasks/{anomalydetectors/cb_detectors => driftdetectors/clusterbased}/drift_detector.py (98%) create mode 100644 src/mlpro/oa/streams/tasks/driftdetectors/drifts/__init__.py create mode 100644 src/mlpro/oa/streams/tasks/driftdetectors/drifts/basics.py create mode 100644 src/mlpro/oa/streams/tasks/driftdetectors/drifts/clusterbased/__init__.py create mode 100644 src/mlpro/oa/streams/tasks/driftdetectors/drifts/clusterbased/basics.py diff --git a/src/mlpro/oa/streams/tasks/anomalydetectors/anomalies/__init__.py b/src/mlpro/oa/streams/tasks/anomalydetectors/anomalies/__init__.py index c495961d0..8cf279a22 100644 --- a/src/mlpro/oa/streams/tasks/anomalydetectors/anomalies/__init__.py +++ b/src/mlpro/oa/streams/tasks/anomalydetectors/anomalies/__init__.py @@ -1,6 +1,5 @@ from mlpro.oa.streams.tasks.anomalydetectors.anomalies.basics import Anomaly from mlpro.oa.streams.tasks.anomalydetectors.anomalies.point import PointAnomaly from mlpro.oa.streams.tasks.anomalydetectors.anomalies.group import GroupAnomaly -from mlpro.oa.streams.tasks.anomalydetectors.anomalies.drift import DriftAnomaly from mlpro.oa.streams.tasks.anomalydetectors.anomalies.contextual import ContextualAnomaly from mlpro.oa.streams.tasks.anomalydetectors.anomalies.clusterbased import * \ No newline at end of file diff --git a/src/mlpro/oa/streams/tasks/anomalydetectors/anomalies/basics.py b/src/mlpro/oa/streams/tasks/anomalydetectors/anomalies/basics.py index 32d6bdaa4..e7c48d191 100644 --- a/src/mlpro/oa/streams/tasks/anomalydetectors/anomalies/basics.py +++ b/src/mlpro/oa/streams/tasks/anomalydetectors/anomalies/basics.py @@ -14,10 +14,11 @@ ## -- 2024-05-07 1.3.1 SK Bug fix related to p_instances ## -- 2024-05-09 1.3.2 DA Bugfix in method Anomaly._update_plot() ## -- 2024-05-22 1.4.0 SK Refactoring +## -- 2025-02-12 1.4.1 DA Code reduction ## ------------------------------------------------------------------------------------------------- """ -Ver. 1.4.0 (2024-05-22) +Ver. 1.4.1 (2025-02-12) This module provides a template class for anomalies to be used in anomaly detection algorithms. """ @@ -26,7 +27,6 @@ from mlpro.bf.plot import Plottable, PlotSettings from mlpro.bf.events import Event from mlpro.bf.streams import Instance -from mlpro.bf.math.properties import PropertyDefinitions, Properties diff --git a/src/mlpro/oa/streams/tasks/anomalydetectors/anomalies/clusterbased/drift.py b/src/mlpro/oa/streams/tasks/anomalydetectors/anomalies/clusterbased/drift.py deleted file mode 100644 index 0db1e1a6f..000000000 --- a/src/mlpro/oa/streams/tasks/anomalydetectors/anomalies/clusterbased/drift.py +++ /dev/null @@ -1,39 +0,0 @@ -## ------------------------------------------------------------------------------------------------- -## -- Project : MLPro - The integrative middleware framework for standardized machine learning -## -- Package : mlpro.oa.tasks.anomalydetectors.anomalies.clusterbased -## -- Module : drift.py -## ------------------------------------------------------------------------------------------------- -## -- History : -## -- yyyy-mm-dd Ver. Auth. Description -## -- 2023-06-08 0.0.0 SK Creation -## -- 2023-09-12 1.0.0 SK Release -## -- 2023-11-21 1.0.1 SK Time Stamp update -## -- 2024-02-25 1.1.0 SK Visualisation update -## -- 2024-04-10 1.2.0 DA/SK Refactoring -## -- 2024-05-22 1.2.1 SK Refactoring -## -- 2024-05-28 1.3.0 SK Refactoring -## ------------------------------------------------------------------------------------------------- - -""" -Ver. 1.3.0 (2024-05-28) - -This module provides a template class for cluster drift to be used in anomaly detection algorithms. -""" - -from mlpro.oa.streams.tasks.anomalydetectors.anomalies.clusterbased.basics import CBAnomaly - - - - - -## ------------------------------------------------------------------------------------------------- -## ------------------------------------------------------------------------------------------------- -class ClusterDrift (CBAnomaly): - """ - Event class to be raised when cluster drift detected. - - """ - - C_NAME = 'Cluster drift Anomaly' - - diff --git a/src/mlpro/oa/streams/tasks/anomalydetectors/anomalies/drift.py b/src/mlpro/oa/streams/tasks/anomalydetectors/anomalies/drift.py deleted file mode 100644 index 2a3efd241..000000000 --- a/src/mlpro/oa/streams/tasks/anomalydetectors/anomalies/drift.py +++ /dev/null @@ -1,34 +0,0 @@ -## ------------------------------------------------------------------------------------------------- -## -- Project : MLPro - The integrative middleware framework for standardized machine learning -## -- Package : mlpro.oa.tasks.anomalydetectors.anomalies -## -- Module : drift.py -## ------------------------------------------------------------------------------------------------- -## -- History : -## -- yyyy-mm-dd Ver. Auth. Description -## -- 2023-06-08 0.0.0 SK Creation -## -- 2023-09-12 1.0.0 SK Release -## -- 2024-04-10 1.2.0 DA/SK Refactoring -## ------------------------------------------------------------------------------------------------- - -""" -Ver. 1.2.0 (2024-04-10) - -This module provides a template class for drift anomaly to be used in anomaly detection algorithms. -""" - -from mlpro.oa.streams.tasks.anomalydetectors.anomalies.basics import Anomaly - - - -## ------------------------------------------------------------------------------------------------- -## ------------------------------------------------------------------------------------------------- -class DriftAnomaly (Anomaly): - """ - Event class to be raised when drift is detected. - """ - - C_NAME = 'Drift' - - - - diff --git a/src/mlpro/oa/streams/tasks/driftdetectors/__init__.py b/src/mlpro/oa/streams/tasks/driftdetectors/__init__.py new file mode 100644 index 000000000..60bc06394 --- /dev/null +++ b/src/mlpro/oa/streams/tasks/driftdetectors/__init__.py @@ -0,0 +1 @@ +from mlpro.oa.streams.tasks.driftdetectors.basics import DriftDetector \ No newline at end of file diff --git a/src/mlpro/oa/streams/tasks/driftdetectors/basics.py b/src/mlpro/oa/streams/tasks/driftdetectors/basics.py new file mode 100644 index 000000000..38bc9f0f1 --- /dev/null +++ b/src/mlpro/oa/streams/tasks/driftdetectors/basics.py @@ -0,0 +1,235 @@ +## ------------------------------------------------------------------------------------------------- +## -- Project : MLPro - The integrative middleware framework for standardized machine learning +## -- Package : mlpro.oa.streams.tasks.driftdetectors +## -- Module : basics.py +## ------------------------------------------------------------------------------------------------- +## -- History : +## -- yyyy-mm-dd Ver. Auth. Description +## -- 2025-02-12 0.1.0 DA Creation +## ------------------------------------------------------------------------------------------------- + +""" +Ver. 0.1.0 (2025-02-12) + +This module provides templates for drift detection to be used in the context of online adaptivity. +""" + +try: + from matplotlib.figure import Figure +except: + class Figure : pass + +from mlpro.bf.plot import PlotSettings +from mlpro.bf.streams import InstDict +from mlpro.bf.various import Log +from mlpro.oa.streams import OAStreamTask +from mlpro.oa.streams.tasks.driftdetectors.drifts import Drift + + + +## ------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- +class DriftDetector (OAStreamTask): + """ + Base class for online anomaly detectors. It raises an event when an + anomaly is detected. + + Parameters + ---------- + p_name : str + Optional name of the task. Default is None. + p_range_max : int + Maximum range of asynchonicity. See class Range. Default is Range.C_RANGE_PROCESS. + p_ada : bool + Boolean switch for adaptivitiy. Default = True. + p_duplicate_data : bool + If True, instances will be duplicated before processing. Default = False. + p_visualize : bool + Boolean switch for visualisation. Default = False. + p_logging + Log level (see constants of class Log). Default: Log.C_LOG_ALL + p_kwargs : dict + Further optional named parameters. + """ + + C_TYPE = 'Drift Detector' + + C_EVENT_DRIFT_ADDED = 'DRIFT_ADDED' + C_EVENT_DRIFT_REMOVED = 'DRIFT_REMOVED' + + C_PLOT_ACTIVE = True + C_PLOT_STANDALONE = False + +## ------------------------------------------------------------------------------------------------- + def __init__( self, + p_name:str = None, + p_range_max = OAStreamTask.C_RANGE_THREAD, + p_ada : bool = True, + p_duplicate_data : bool = False, + p_visualize : bool = False, + p_logging=Log.C_LOG_ALL, + **p_kwargs ): + + super().__init__( p_name = p_name, + p_range_max = p_range_max, + p_ada = p_ada, + p_duplicate_data = p_duplicate_data, + p_visualize = p_visualize, + p_logging = p_logging, + **p_kwargs ) + + self._drift_id = 0 + self._drifts = {} + + +## ------------------------------------------------------------------------------------------------- + def _run(self, p_inst : InstDict): + pass + + +## ------------------------------------------------------------------------------------------------- + def _get_next_drift_id(self): + """ + Methd that returns the id of the next drift. + + Returns + ------- + drift_id : int + """ + + self._drift_id +=1 + return self._drift_id + + +## ------------------------------------------------------------------------------------------------- + def get_drifts(self): + """ + Method to return the current list of drifts. + + Returns + ------- + drifts : dict[Drift] + Current dictionary of drifts. + """ + + return self._drifts + + +## ------------------------------------------------------------------------------------------------- + def _buffer_drift(self, p_drift:Drift): + """ + Method to be used internally to add a new drift object. Please use as part of your algorithm. + + Parameters + ---------- + p_drift : Drift + Drift object to be added. + + Returns + ------- + p_drift Drift + Enriched drift object + """ + + p_drift.id = self._get_next_drift_id() + self._drifts[p_drift.id] = p_drift + return p_drift + + +## ------------------------------------------------------------------------------------------------- + def remove_drift(self, p_drift:Drift): + """ + Method to remove an existing drift object. Please use as part of your algorithm. + + Parameters + ---------- + p_drift : Drift + Drift object to be removed. + """ + + p_drift.remove_plot(p_refresh=True) + del self._drifts[p_drift.id] + + +## ------------------------------------------------------------------------------------------------- + def _raise_drift_event( self, + p_event_id : str, + p_drift : Drift ): + """ + Specialized method to raise drift events. + + Parameters + ---------- + p_event_id : str + Event id. See class constants C_EVENT_DRIFT_ADDED/REMOVED. + p_drift : Drift + Drift event object to be raised. + """ + + self._buffer_drift( p_drift = p_drift ) + + if self.get_visualization(): + p_drift.init_plot( p_figure=self._figure, p_plot_settings=self.get_plot_settings() ) + + return super()._raise_event( p_event_id = p_event_id, p_event_object = p_drift ) + + +## ------------------------------------------------------------------------------------------------- + def init_plot(self, p_figure: Figure = None, p_plot_settings: PlotSettings = None): + + if not self.get_visualization(): return + + self._plot_ax_xlim = None + self._plot_ax_ylim = None + self._plot_ax_zlim = None + + #super().init_plot( p_figure=p_figure, p_plot_settings=p_plot_settings) + + for drift in self._drifts.values(): + drift.init_plot(p_figure=p_figure, p_plot_settings = p_plot_settings) + + +## ------------------------------------------------------------------------------------------------- + def update_plot(self, p_inst : InstDict = None, **p_kwargs): + + if not self.get_visualization(): return + + # super().update_plot(p_inst, **p_kwargs) + + axes = self._plot_settings.axes + + ax_xlim_new = axes.get_xlim() + if self._plot_settings.view != PlotSettings.C_VIEW_ND: + axlimits_changed = ( self._plot_ax_xlim is None ) or ( self._plot_ax_xlim != ax_xlim_new ) + else: + axlimits_changed = False + + ax_ylim_new = axes.get_ylim() + axlimits_changed = axlimits_changed or ( self._plot_ax_ylim is None ) or ( self._plot_ax_ylim != ax_ylim_new ) + try: + ax_zlim_new = axes.get_zlim() + axlimits_changed = axlimits_changed or ( self._plot_ax_zlim is None ) or ( self._plot_ax_zlim != ax_zlim_new ) + except: + ax_zlim_new = None + + self._plot_ax_xlim = ax_xlim_new + self._plot_ax_ylim = ax_ylim_new + self._plot_ax_zlim = ax_zlim_new + + for drift in self._drifts.values(): + drift.update_plot( p_axlimits_changed = axlimits_changed, + p_xlim = ax_xlim_new, + p_ylim = ax_ylim_new, + p_zlim = ax_zlim_new, + **p_kwargs ) + + +## ------------------------------------------------------------------------------------------------- + def remove_plot(self, p_refresh: bool = True): + + if not self.get_visualization(): return + + # super().remove_plot( p_refresh = p_refresh ) + + for drift in self._drifts.values(): + drift.remove_plot(p_refresh=p_refresh) \ No newline at end of file diff --git a/src/mlpro/oa/streams/tasks/driftdetectors/clusterbased/__init__.py b/src/mlpro/oa/streams/tasks/driftdetectors/clusterbased/__init__.py new file mode 100644 index 000000000..c08a54cbc --- /dev/null +++ b/src/mlpro/oa/streams/tasks/driftdetectors/clusterbased/__init__.py @@ -0,0 +1 @@ +from mlpro.oa.streams.tasks.driftdetectors.clusterbased.basics import DriftDetectorCB \ No newline at end of file diff --git a/src/mlpro/oa/streams/tasks/driftdetectors/clusterbased/basics.py b/src/mlpro/oa/streams/tasks/driftdetectors/clusterbased/basics.py new file mode 100644 index 000000000..ed3036c8f --- /dev/null +++ b/src/mlpro/oa/streams/tasks/driftdetectors/clusterbased/basics.py @@ -0,0 +1,83 @@ +## -- ---------------------------------------------------------------------------------------------- +## -- Project : MLPro - The integrative middleware framework for standardized machine learning +## -- Package : mlpro.oa.streams.tasks.driftdetectors.clusterbased +## -- Module : basics.py +## ------------------------------------------------------------------------------------------------- +## -- History : +## -- yyyy-mm-dd Ver. Auth. Description +## -- 2025-02-12 0.1.0 DA Creation +## ------------------------------------------------------------------------------------------------- + +""" +Ver. 0.1.0 (2025-02-12) + +This module provides template for cluster-based drift detection algorithms to be used in the context of online adaptivity. +""" + +from mlpro.bf.various import Log +from mlpro.bf.math.properties import * + +from mlpro.oa.streams.basics import OAStreamTask +from mlpro.oa.streams.tasks.driftdetectors.basics import DriftDetector +from mlpro.oa.streams.tasks.clusteranalyzers.basics import ClusterAnalyzer + + + + +## ------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- +class DriftDetectorCB (DriftDetector): + """ + This is the base class for online-adaptive cluster-based drift detectors. It raises an event + when a drift is detected in a cluster dataset. + + Parameters + ---------- + p_clusterer : ClusterAnalyzer + Related cluster analyzer providing its clusters as the basis for drift detection + p_name : str + Optional name of the task. Default is None. + p_range_max : int + Maximum range of asynchonicity. See class Range. Default is Range.C_RANGE_PROCESS. + p_ada : bool + Boolean switch for adaptivitiy. Default = True. + p_duplicate_data : bool + If True, instances will be duplicated before processing. Default = False. + p_visualize : bool + Boolean switch for visualisation. Default = False. + p_logging + Log level (see constants of class Log). Default: Log.C_LOG_ALL + p_kwargs : dict + Further optional named parameters. + """ + + C_TYPE = 'Cluster-based Drift Detector' + + # List of cluster properties necessary for the algorithm + C_REQ_CLUSTER_PROPERTIES : PropertyDefinitions = [] + +## ------------------------------------------------------------------------------------------------- + def __init__( self, + p_clusterer : ClusterAnalyzer, + p_name : str = None, + p_range_max = OAStreamTask.C_RANGE_THREAD, + p_ada : bool = True, + p_duplicate_data : bool = False, + p_visualize : bool = False, + p_logging=Log.C_LOG_ALL, + **p_kwargs): + + super().__init__(p_name = p_name, + p_range_max = p_range_max, + p_ada = p_ada, + p_duplicate_data = p_duplicate_data, + p_visualize = p_visualize, + p_logging = p_logging, + **p_kwargs) + + self._clusterer = p_clusterer + unknown_prop = self._clusterer.align_cluster_properties(p_properties=self.C_REQ_CLUSTER_PROPERTIES) + + if len(unknown_prop) > 0: + raise RuntimeError("The following cluster properties need to be provided by the clusterer: ", unknown_prop) + \ No newline at end of file diff --git a/src/mlpro/oa/streams/tasks/anomalydetectors/cb_detectors/drift_detector.py b/src/mlpro/oa/streams/tasks/driftdetectors/clusterbased/drift_detector.py similarity index 98% rename from src/mlpro/oa/streams/tasks/anomalydetectors/cb_detectors/drift_detector.py rename to src/mlpro/oa/streams/tasks/driftdetectors/clusterbased/drift_detector.py index a28ffd8ed..b88be9f5f 100644 --- a/src/mlpro/oa/streams/tasks/anomalydetectors/cb_detectors/drift_detector.py +++ b/src/mlpro/oa/streams/tasks/driftdetectors/clusterbased/drift_detector.py @@ -1,6 +1,6 @@ ## -- ---------------------------------------------------------------------------------------------- ## -- Project : MLPro - The integrative middleware framework for standardized machine learning -## -- Package : mlpro.oa.tasks.anomalydetectors.cb_detectors +## -- Package : mlpro.oa.tasks.driftdetectors.clusterbased ## -- Module : drift_detector.py ## ------------------------------------------------------------------------------------------------- ## -- History : @@ -9,22 +9,25 @@ ## -- 2023-09-12 1.0.0 SK Release ## -- 2024-04-10 1.1.0 DA/SK Refactoring ## -- 2024-05-28 1.2.0 SK Refactoring +## -- 2025-02-12 2.0.0 DA Relocation and refactoring ## ------------------------------------------------------------------------------------------------- """ -Ver. 1.2.0 (2024-05-28) +Ver. 2.0.0 (2025-02-12) -This module provides cluster drift detector algorithm. +This module provides a cluster-based drift detector algorithm. """ +import time + from mlpro.oa.streams.basics import * from mlpro.oa.streams.tasks.anomalydetectors.cb_detectors.basics import AnomalyDetectorCB -from mlpro.oa.streams.tasks.anomalydetectors.anomalies.clusterbased.drift import ClusterDrift +from mlpro.oa.streams.tasks.anomalydetectors.anomalies.clusterbased.drifts import ClusterDrift from mlpro.oa.streams.tasks.clusteranalyzers.basics import ClusterAnalyzer from mlpro.bf.streams import Instance, InstDict from mlpro.bf.math.properties import * from mlpro.oa.streams.tasks.clusteranalyzers.clusters.properties.centroid import cprop_centroid2 -import time + diff --git a/src/mlpro/oa/streams/tasks/driftdetectors/drifts/__init__.py b/src/mlpro/oa/streams/tasks/driftdetectors/drifts/__init__.py new file mode 100644 index 000000000..7651d8c8f --- /dev/null +++ b/src/mlpro/oa/streams/tasks/driftdetectors/drifts/__init__.py @@ -0,0 +1,2 @@ +from mlpro.oa.streams.tasks.driftdetectors.drifts.basics import Drift +from mlpro.oa.streams.tasks.driftdetectors.drifts.clusterbased import * \ No newline at end of file diff --git a/src/mlpro/oa/streams/tasks/driftdetectors/drifts/basics.py b/src/mlpro/oa/streams/tasks/driftdetectors/drifts/basics.py new file mode 100644 index 000000000..340c033dc --- /dev/null +++ b/src/mlpro/oa/streams/tasks/driftdetectors/drifts/basics.py @@ -0,0 +1,62 @@ +## ------------------------------------------------------------------------------------------------- +## -- Project : MLPro - The integrative middleware framework for standardized machine learning +## -- Package : mlpro.oa.tasks.driftdetectors.drifts +## -- Module : basics.py +## ------------------------------------------------------------------------------------------------- +## -- History : +## -- yyyy-mm-dd Ver. Auth. Description +## -- 2025-02-12 1.0.0 DA Creation +## ------------------------------------------------------------------------------------------------- + +""" +Ver. 1.0.0 (2025-02-12) + +This module provides a template class for types of data drift to be used in drift detection algorithms. +""" + +from datetime import datetime + +from mlpro.bf.various import Id +from mlpro.bf.plot import Plottable +from mlpro.bf.events import Event + + + + + +## ------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- +class Drift (Id, Event, Plottable): + """ + This is the base class for drift events which can be raised by the drift detectors when a + drift is detected. + + Parameters + ---------- + p_id : int + Drift ID. Default value = 0. + p_tstamp : datetime + Time stamp of drift detection. Default = None. + p_visualize : bool + Boolean switch for visualisation. Default = False. + p_raising_object : object + Reference of the object raised. Default = None. + **p_kwargs + Further optional keyword arguments. + """ + + C_TYPE = 'Drift' + C_PLOT_STANDALONE = False + +## ------------------------------------------------------------------------------------------------- + def __init__(self, + p_id : int = 0, + p_tstamp : datetime = None, + p_visualize : bool = False, + p_raising_object : object = None, + **p_kwargs): + + Id.__init__( self, p_id = p_id ) + Event.__init__( self, p_raising_object=p_raising_object, + p_tstamp=p_tstamp, **p_kwargs) + Plottable.__init__( self, p_visualize = p_visualize ) diff --git a/src/mlpro/oa/streams/tasks/driftdetectors/drifts/clusterbased/__init__.py b/src/mlpro/oa/streams/tasks/driftdetectors/drifts/clusterbased/__init__.py new file mode 100644 index 000000000..5a486ce5b --- /dev/null +++ b/src/mlpro/oa/streams/tasks/driftdetectors/drifts/clusterbased/__init__.py @@ -0,0 +1 @@ +from mlpro.oa.streams.tasks.driftdetectors.drifts.clusterbased.basics import CBDrift \ No newline at end of file diff --git a/src/mlpro/oa/streams/tasks/driftdetectors/drifts/clusterbased/basics.py b/src/mlpro/oa/streams/tasks/driftdetectors/drifts/clusterbased/basics.py new file mode 100644 index 000000000..440654589 --- /dev/null +++ b/src/mlpro/oa/streams/tasks/driftdetectors/drifts/clusterbased/basics.py @@ -0,0 +1,126 @@ +## ------------------------------------------------------------------------------------------------- +## -- Project : MLPro - The integrative middleware framework for standardized machine learning +## -- Package : mlpro.oa.tasks.driftdetectors.drifts.clusterbased +## -- Module : basics.py +## ------------------------------------------------------------------------------------------------- +## -- History : +## -- yyyy-mm-dd Ver. Auth. Description +## -- 2025-02-12 1.0.0 DA Creation +## ------------------------------------------------------------------------------------------------- + +""" +Ver. 1.0.0 (2025-02-12) + +This module provides a template class for cluster-based drifts to be used in cluster-based drift +detection algorithms. +""" + +from datetime import datetime + +try: + from matplotlib.figure import Figure +except: + class Figure : pass + +from mlpro.bf.mt import PlotSettings +from mlpro.oa.streams.tasks.driftdetectors.drifts.basics import Drift +from mlpro.oa.streams.tasks.clusteranalyzers.clusters.basics import Cluster + + + + + +## ------------------------------------------------------------------------------------------------- +## ------------------------------------------------------------------------------------------------- +class CBDrift (Drift): + """ + Sub-type for cluster-based drift events. + + Parameters + ---------- + p_id : int + Drift ID. Default value = 0. + p_tstamp : datetime + Time stamp of drift detection. Default = None. + p_visualize : bool + Boolean switch for visualisation. Default = False. + p_raising_object : object + Reference of the object raised. Default = None. + p_clusters : dict[Cluster] + Clusters associated with the anomaly. Default = None. + p_properties : dict + Poperties of clusters associated with the anomaly. Default = None. + **p_kwargs + Further optional keyword arguments. + """ + + C_NAME = 'Cluster-based Drift' + C_PLOT_ACTIVE = True + +## ------------------------------------------------------------------------------------------------- + def __init__(self, + p_id : int = 0, + p_tstamp : datetime = None, + p_visualize : bool = False, + p_raising_object : object = None, + p_clusters : dict[Cluster] = None, + p_properties : dict = None, + **p_kwargs): + + super().__init__( p_id = p_id, + p_tstamp = p_tstamp, + p_visualize = p_visualize, + p_raising_object = p_raising_object, + **p_kwargs ) + + self._clusters : dict[Cluster] = p_clusters + self._properties : dict = p_properties + + +## ------------------------------------------------------------------------------------------------- + def get_clusters(self) -> dict[Cluster]: + """ + Method that returns the clusters associated with the drift. + + Returns + ------- + dict[Cluster] + Dictionary of clusters. + """ + return self._clusters + + +## ------------------------------------------------------------------------------------------------- + def get_properties(self) -> dict: + """ + Method that returns the properties of clusters associated with the drift. + + Returns + ------- + dict + Dictionary of properties. + """ + return self._properties + + +## ------------------------------------------------------------------------------------------------- + def _init_plot_2d(self, p_figure: Figure, p_settings: PlotSettings): + super()._init_plot_2d(p_figure=p_figure, p_settings=p_settings) + + cluster : Cluster = None + + for cluster in self._clusters.values(): + cluster.color = "red" + + +## ------------------------------------------------------------------------------------------------- + def _init_plot_3d(self, p_figure: Figure, p_settings: PlotSettings): + super()._init_plot_3d(p_figure=p_figure, p_settings=p_settings) + + cluster : Cluster = None + + for cluster in self._clusters.values(): + cluster.color = "red" + + +