commit for version used in evaluation of thesis
This commit is contained in:
commit
72635dc7b9
27 changed files with 6084 additions and 0 deletions
98
internal/detect/copod.go
Normal file
98
internal/detect/copod.go
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
// Package detect provides anomaly detection algorithms and ensemble logic.
|
||||
package detect
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"codeberg.org/pata1704/copod"
|
||||
"codeberg.org/pata1704/guenther/pkg/types"
|
||||
)
|
||||
|
||||
// COPODDetector implements the AnomalyDetector interface by wrapping the
|
||||
// external codeberg.org/pata1704/copod package.
|
||||
//
|
||||
// Streaming mode: Score calls Update internally, so the sliding-window buffer
|
||||
// stays current without requiring a separate Update call. Callers (like SEAD)
|
||||
// only need to call Score per time step.
|
||||
//
|
||||
// Fit seeds the buffer with a batch of normal vectors. If Fit is not called
|
||||
// the detector starts cold and returns score=0 until the buffer has enough
|
||||
// points (controlled by bufferSize in the underlying library).
|
||||
type COPODDetector struct {
|
||||
detector *copod.Detector
|
||||
}
|
||||
|
||||
// NewCOPODDetector initialises the streaming COPOD detector wrapper.
|
||||
//
|
||||
// - bufferSize: sliding-window capacity. Recommended: 100–200.
|
||||
// - threshold: score cutoff for standalone IsAnomaly. When used inside
|
||||
// SEAD the threshold is ignored (SEAD applies its own adaptive threshold).
|
||||
func NewCOPODDetector(bufferSize int, threshold float64) (*COPODDetector, error) {
|
||||
det, err := copod.NewDetector(bufferSize, threshold)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("copod: initialize wrapped detector: %w", err)
|
||||
}
|
||||
return &COPODDetector{
|
||||
detector: det,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Fit seeds the COPOD history buffer with a slice of labelled-normal vectors.
|
||||
func (c *COPODDetector) Fit(vectors []types.FeatureVector) error {
|
||||
for _, v := range vectors {
|
||||
if err := c.update(v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update adds a single observation to the sliding window.
|
||||
// Safe to call concurrently with Score.
|
||||
func (c *COPODDetector) Update(vector types.FeatureVector) error {
|
||||
return c.update(vector)
|
||||
}
|
||||
|
||||
// Score computes the COPOD anomaly score for the given vector and
|
||||
// simultaneously updates the internal sliding window with the scored vector.
|
||||
//
|
||||
// The self-update ensures COPOD's buffer reflects the current data stream
|
||||
// without requiring a separate Update call after every Score. This is
|
||||
// consistent with the RRCF and IsolationForest detectors which also
|
||||
// update themselves inside Score.
|
||||
func (c *COPODDetector) Score(vector types.FeatureVector) (types.AnomalyResult, error) {
|
||||
vec := copod.FeatureVector{
|
||||
NormalizedVector: vector.NormalizedVector,
|
||||
Timestamp: vector.Timestamp,
|
||||
}
|
||||
|
||||
// Score first, then append to the buffer so the scored point does not
|
||||
// bias its own copula calculation (score-then-insert, same as RRCF).
|
||||
res, err := c.detector.Score(vec)
|
||||
if err != nil {
|
||||
return types.AnomalyResult{}, fmt.Errorf("copod: score: %w", err)
|
||||
}
|
||||
|
||||
if err := c.update(vector); err != nil {
|
||||
// Log but don't fail: the score is already computed.
|
||||
log.Printf("copod: update after score: %v", err)
|
||||
}
|
||||
|
||||
return types.AnomalyResult{
|
||||
Timestamp: res.Timestamp,
|
||||
Score: res.Score,
|
||||
IsAnomaly: res.IsAnomaly,
|
||||
Confidence: res.Confidence,
|
||||
Method: res.Method,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// update is the internal helper that adds vector to the copod sliding window.
|
||||
func (c *COPODDetector) update(vector types.FeatureVector) error {
|
||||
vec := copod.FeatureVector{
|
||||
NormalizedVector: vector.NormalizedVector,
|
||||
Timestamp: vector.Timestamp,
|
||||
}
|
||||
return c.detector.Update(vec)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue