Skip to content

Commit

Permalink
Refact: Separation of anomaly detection from drift detection #1133
Browse files Browse the repository at this point in the history
  • Loading branch information
detlefarend committed Feb 14, 2025
1 parent e756284 commit 86df600
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 405 deletions.

This file was deleted.

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/mlpro/bf/plot/backends/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from mlpro.bf.plot.backends.basics import WindowState, WSMINIMIZED, WSMAXIMIZED, WSNORMAL, WindowGeometry, PlotBackend
from mlpro.bf.plot.backends.tkagg import PlotBackendTkAgg
from mlpro.bf.plot.backends.qtagg import PlotBackendqtagg
from mlpro.bf.plot.backends.qtagg import PlotBackendqtagg, PlotBackendQtAgg
8 changes: 8 additions & 0 deletions src/mlpro/bf/plot/backends/qtagg.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,11 @@ def _figure_set_geometry_default(self, p_figure : Figure, p_geometry : WindowGeo
state_qt = QtCore.Qt.WindowNoState

window.setWindowState(state_qt)





## -------------------------------------------------------------------------------------------------
## -------------------------------------------------------------------------------------------------
class PlotBackendQtAgg (PlotBackendqtagg): pass
2 changes: 1 addition & 1 deletion src/mlpro/oa/streams/tasks/anomalydetectors/basics.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ def init_plot(self, p_figure: Figure = None, p_plot_settings: PlotSettings = Non
self._plot_ax_ylim = None
self._plot_ax_zlim = None

# super().init_plot( p_figure=p_figure, p_plot_settings=p_plot_settings)
super().init_plot( p_figure=p_figure, p_plot_settings=p_plot_settings)

for anomaly in self._anomalies.values():
anomaly.init_plot(p_figure=p_figure, p_plot_settings = p_plot_settings)
Expand Down
121 changes: 59 additions & 62 deletions src/mlpro/oa/streams/tasks/anomalydetectors/paga_detectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,32 @@
## -- 2024-04-10 1.2.0 DA/SK Code review
## -- 2024-05-07 1.2.1 SK Bug fix on groupanomaly visualisation
## -- 2024-08-12 1.3.0 DA Review and adjustments on documentation
## -- 2025-02-14 1.4.0 DA Refactoring
## -------------------------------------------------------------------------------------------------

"""
Ver. 1.3.0 (2024-08-12)
Ver. 1.4.0 (2025-02-14)
This module provides a ready-to-use detector for point and group anomalies.
"""

from mlpro.oa.streams.basics import *
from mlpro.bf.various import Log
from mlpro.bf.exceptions import ImplementationError
from mlpro.bf.streams import Instance

from mlpro.oa.streams.basics import StreamTask
from mlpro.oa.streams.tasks.anomalydetectors.basics import AnomalyDetector
from mlpro.oa.streams.tasks.anomalydetectors.anomalies import *
from mlpro.oa.streams.tasks.anomalydetectors.anomalies import Anomaly, PointAnomaly, GroupAnomaly



## -------------------------------------------------------------------------------------------------
## -------------------------------------------------------------------------------------------------
class AnomalyDetectorPAGA (AnomalyDetector):
"""
This class implements a ready-to-use detector for point and group anomalies.
This class is an extended template dedicated to point and group anomaly detection. Child
class just need to focus on point anomaly detection. Groups of point anomalies are automatically
detected and raised as group anomalies as part of method _buffer_anomaly().
Parameters
----------
Expand All @@ -52,7 +59,7 @@ class AnomalyDetectorPAGA (AnomalyDetector):
Further optional named parameters.
"""

C_NAME = 'Anomaly Detector'
C_NAME = 'Anomaly Detector PAGA'

## -------------------------------------------------------------------------------------------------
def __init__( self,
Expand All @@ -73,10 +80,10 @@ def __init__( self,
p_logging = p_logging,
**p_kwargs )

self.group_anomalies : list[Anomaly] = []
self.group_anomalies_instances : list[Instance] = []
self.group_ano_scores = []
self.group_anomaly_det = p_group_anomaly_det
self._group_anomalies : list[Anomaly] = []
self._group_anomalies_instances : list[Instance] = []
self._group_ano_scores = []
self._group_anomaly_det = p_group_anomaly_det


## -------------------------------------------------------------------------------------------------
Expand All @@ -88,72 +95,62 @@ def _buffer_anomaly(self, p_anomaly):
----------
p_anomaly : Anomaly
Anomaly object to be added.
Returns
-------
p_anomaly : Anomaly
Modified Anomaly object.
"""

if self.group_anomaly_det:
self.group_anomalies.append(p_anomaly)
self.group_anomalies_instances.append(p_anomaly.get_instances()[-1])
self.group_ano_scores.append(p_anomaly.get_ano_scores())
if type(p_anomaly) != PointAnomaly:
raise ImplementationError('The AnomalyDetectorPAGA class only supports point anomalies.')


if self._group_anomaly_det:
self._group_anomalies.append(p_anomaly)
self._group_anomalies_instances.append(p_anomaly.get_instances()[-1])
self._group_ano_scores.append(p_anomaly.get_ano_scores())

if len(self.group_anomalies_instances) > 1:
if len(self._group_anomalies_instances) > 1:

inst_2 = self.group_anomalies_instances[-1]
second = inst_2.get_id()
inst_1 = self.group_anomalies_instances[-2]
first = inst_1.get_id()
inst_2 = self._group_anomalies_instances[-1]
second = inst_2.id
inst_1 = self._group_anomalies_instances[-2]
first = inst_1.id

if int(second) - 1 == int(first):

if len(self.group_anomalies_instances) == 3:
if len(self._group_anomalies_instances) == 3:

for i in range(2):
self.remove_anomaly(self.group_anomalies[i])
self._remove_anomaly(self._group_anomalies[i])

self._ano_id -= 2
anomaly = GroupAnomaly( p_instances=self.group_anomalies_instances,
p_ano_scores=self.group_ano_scores, p_visualize=self._visualize,
p_raising_object=self,
p_det_time=str(inst_2.get_tstamp()) )
anomaly.id = self._get_next_anomaly_id()
self._anomalies[anomaly.id] = anomaly
self.group_anomalies = []
self.group_anomalies.append(anomaly)
return anomaly

elif len(self.group_anomalies_instances) > 3:
self.group_anomalies[0].set_instances(self.group_anomalies_instances, self.group_ano_scores)
self.group_anomalies.pop(-1)
return self.group_anomalies[0]
groupanomaly = GroupAnomaly( p_instances=self._group_anomalies_instances,
p_ano_scores=self._group_ano_scores, p_visualize=self._visualize,
p_raising_object=self,
p_tstampt=inst_2.tstamp )

super()._buffer_anomaly( p_anomaly = groupanomaly )

self._group_anomalies = []
self._group_anomalies.append(groupanomaly)

elif len(self._group_anomalies_instances) > 3:
self._group_anomalies[0].set_instances(self._group_anomalies_instances, self._group_ano_scores)
self._group_anomalies.pop(-1)
return self._group_anomalies[0]

else:
p_anomaly.set_id( p_id = self._get_next_anomaly_id() )
self._anomalies[p_anomaly.get_id()] = p_anomaly
return p_anomaly

super()._buffer_anomaly( p_anomaly = p_anomaly)

else:
for anomaly in self.group_anomalies:
if isinstance(anomaly, GroupAnomaly):
anomaly.plot_update = False
self.group_anomalies = []
self.group_anomalies_instances = []
self.group_ano_scores = []
self.group_anomalies.append(p_anomaly)
self.group_anomalies_instances.append(p_anomaly.get_instances()[-1])
self.group_ano_scores.append(p_anomaly.get_ano_scores())
p_anomaly.id = self._get_next_anomaly_id()
self._anomalies[p_anomaly.id] = p_anomaly
return p_anomaly
for groupanomaly in self._group_anomalies:
if isinstance(groupanomaly, GroupAnomaly):
groupanomaly.plot_update = False
self._group_anomalies = []
self._group_anomalies_instances = []
self._group_ano_scores = []
self._group_anomalies.append(p_anomaly)
self._group_anomalies_instances.append(p_anomaly.get_instances()[-1])
self._group_ano_scores.append(p_anomaly.get_ano_scores())
super()._buffer_anomaly( p_anomaly = p_anomaly )
else:
p_anomaly.id = self._get_next_anomaly_id()
self._anomalies[p_anomaly.id] = p_anomaly
return p_anomaly

super()._buffer_anomaly( p_anomaly = p_anomaly)
else:
p_anomaly.id = self._get_next_anomaly_id()
self._anomalies[p_anomaly.id] = p_anomaly
return p_anomaly
super()._buffer_anomaly( p_anomaly = p_anomaly)
2 changes: 1 addition & 1 deletion src/mlpro/oa/streams/tasks/driftdetectors/basics.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ def init_plot(self, p_figure: Figure = None, p_plot_settings: PlotSettings = Non
self._plot_ax_ylim = None
self._plot_ax_zlim = None

#super().init_plot( p_figure=p_figure, p_plot_settings=p_plot_settings)
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)
Expand Down

0 comments on commit 86df600

Please sign in to comment.