private protected override void CloneCore(TState state) { base.CloneCore(state); Contracts.Assert(state is AnomalyDetectionStateBase); var stateLocal = state as AnomalyDetectionStateBase; stateLocal.LogMartingaleUpdateBuffer = LogMartingaleUpdateBuffer.Clone(); stateLocal.RawScoreBuffer = RawScoreBuffer.Clone(); }
private protected sealed override void TransformCore(ref TInput input, FixedSizeQueue <TInput> windowedBuffer, long iteration, ref VBuffer <Double> dst) { var outputLength = Parent.OutputLength; Host.Assert(outputLength >= 2); var result = VBufferEditor.Create(ref dst, outputLength); float rawScore = 0; for (int i = 0; i < outputLength; ++i) { result.Values[i] = Double.NaN; } // Step 1: Computing the raw anomaly score result.Values[1] = ComputeRawAnomalyScore(ref input, windowedBuffer, iteration); if (Double.IsNaN(result.Values[1])) { result.Values[0] = 0; } else { if (WindowSize > 0) { // Step 2: Computing the p-value score rawScore = (float)result.Values[1]; if (Parent.ThresholdScore == AlertingScore.RawScore) { switch (Parent.Side) { case AnomalySide.Negative: rawScore = (float)(-result.Values[1]); break; case AnomalySide.Positive: break; default: rawScore = (float)Math.Abs(result.Values[1]); break; } } else { result.Values[2] = ComputeKernelPValue(rawScore); switch (Parent.Side) { case AnomalySide.Negative: result.Values[2] = 1 - result.Values[2]; break; case AnomalySide.Positive: break; default: result.Values[2] = Math.Min(result.Values[2], 1 - result.Values[2]); break; } // Keeping the p-value in the safe range if (result.Values[2] < SequentialAnomalyDetectionTransformBase <TInput, TState> .MinPValue) { result.Values[2] = SequentialAnomalyDetectionTransformBase <TInput, TState> .MinPValue; } else if (result.Values[2] > SequentialAnomalyDetectionTransformBase <TInput, TState> .MaxPValue) { result.Values[2] = SequentialAnomalyDetectionTransformBase <TInput, TState> .MaxPValue; } RawScoreBuffer.AddLast(rawScore); // Step 3: Computing the martingale value if (Parent.Martingale != MartingaleType.None && Parent.ThresholdScore == AlertingScore.MartingaleScore) { Double martingaleUpdate = 0; switch (Parent.Martingale) { case MartingaleType.Power: martingaleUpdate = Parent.LogPowerMartigaleBettingFunc(result.Values[2], Parent.PowerMartingaleEpsilon); break; case MartingaleType.Mixture: martingaleUpdate = Parent.LogMixtureMartigaleBettingFunc(result.Values[2]); break; } if (LogMartingaleUpdateBuffer.Count == 0) { for (int i = 0; i < LogMartingaleUpdateBuffer.Capacity; ++i) { LogMartingaleUpdateBuffer.AddLast(martingaleUpdate); } _logMartingaleValue += LogMartingaleUpdateBuffer.Capacity * martingaleUpdate; } else { _logMartingaleValue += martingaleUpdate; _logMartingaleValue -= LogMartingaleUpdateBuffer.PeekFirst(); LogMartingaleUpdateBuffer.AddLast(martingaleUpdate); } result.Values[3] = Math.Exp(_logMartingaleValue); } } } // Generating alert bool alert = false; if (RawScoreBuffer.IsFull) // No alert until the buffer is completely full. { switch (Parent.ThresholdScore) { case AlertingScore.RawScore: alert = rawScore >= Parent.AlertThreshold; break; case AlertingScore.PValueScore: alert = result.Values[2] <= Parent.AlertThreshold; break; case AlertingScore.MartingaleScore: alert = (Parent.Martingale != MartingaleType.None) && (result.Values[3] >= Parent.AlertThreshold); if (alert) { if (_martingaleAlertCounter > 0) { alert = false; } else { _martingaleAlertCounter = Parent.WindowSize; } } _martingaleAlertCounter--; _martingaleAlertCounter = _martingaleAlertCounter < 0 ? 0 : _martingaleAlertCounter; break; } } result.Values[0] = Convert.ToDouble(alert); } dst = result.Commit(); }