/** * Given a list of anomaly scores return a list of averaged records. * anomalyScores is assumed to be a list of records of the form: * <pre> * Sample: * dt = Tuple(2013, 8, 10, 23, 0) --> Date Fields * sample = (double) 6.0 * metric(avg) = (double) 1.0 * </pre> * * @param anomalyScores List of {@link Sample} objects (described contents above) * @param windowSize Count of historical items over which to compute the average * * @return Each record in the returned list contains [datetime field, value, averaged score] */ public AveragedAnomalyRecordList AnomalyScoreMovingAverage(List <Sample> anomalyScores, int windowSize) { List <double> historicalValues = new List <double>(); double total = 0.0; List <Sample> averagedRecordList = new List <Sample>(); foreach (Sample record in anomalyScores) { //////////////////////////////////////////////////////////////////////////////////////////// // Python version has check for malformed records here, but can't happen in java version. // //////////////////////////////////////////////////////////////////////////////////////////// MovingAverage.Calculation calc = MovingAverage.Compute(historicalValues, total, record.score, windowSize); Sample avgRecord = new Sample( record.date, record.value, calc.GetAverage()); averagedRecordList.Add(avgRecord); total = calc.GetTotal(); if (LOG.IsDebugEnabled) { LOG.Debug(string.Format("Aggregating input record: {0}, Result: {1}", record, averagedRecordList[averagedRecordList.Count - 1])); } } return(new AveragedAnomalyRecordList(averagedRecordList, historicalValues, total)); }
/** * Compute updated probabilities for anomalyScores using the given params. * * @param anomalyScores a list of records. Each record is a list with a {@link Sample} containing the * following three elements: [timestamp, value, score] * @param params Associative <see cref="NamedTuple"/> returned by the {@link AnomalyLikelihoodMetrics} from * {@link #estimateAnomalyLikelihoods(List, int, int)} * @return */ public AnomalyLikelihoodMetrics UpdateAnomalyLikelihoods(List <Sample> anomalyScores, AnomalyParams @params) { int anomalySize = anomalyScores.Count; if (LOG.IsDebugEnabled) { LOG.Debug("in updateAnomalyLikelihoods"); LOG.Debug(string.Format("Number of anomaly scores: {0}", anomalySize)); LOG.Debug(string.Format("First 20: {0}", anomalyScores.SubList(0, Math.Min(20, anomalySize)))); LOG.Debug(string.Format("Params: {0}", @params)); } if (anomalyScores.Count == 0) { throw new ArgumentException("Must have at least one anomaly score."); } if (!IsValidEstimatorParams(@params)) { throw new ArgumentException("\"params\" is not a valid parameter structure"); } double[] histLikelihoods; if ((histLikelihoods = @params.HistoricalLikelihoods()) == null || histLikelihoods.Length == 0) { Parameters anomalyParameters = Parameters.Empty(); anomalyParameters.SetParameterByKey(Parameters.KEY.ANOMALY_KEY_DIST, @params.Distribution()); anomalyParameters.SetParameterByKey(Parameters.KEY.ANOMALY_KEY_MVG_AVG, @params.MovingAverage()); anomalyParameters.SetParameterByKey(Parameters.KEY.ANOMALY_KEY_HIST_LIKE, histLikelihoods = new double[] { 1 }); @params = new AnomalyParams(anomalyParameters); //@params = new NamedTuple( // new string[] { "distribution", "movingAverage", "historicalLikelihoods" }, // @params.Distribution(), // @params.MovingAverage(), // histLikelihoods = new double[] { 1 }); } // Compute moving averages of these new scores using the previous values // as well as likelihood for these scores using the old estimator MovingAverage mvgAvg = (MovingAverage)@params.MovingAverage(); List <double> historicalValues = mvgAvg.GetSlidingWindow(); double total = mvgAvg.GetTotal(); int windowSize = mvgAvg.GetWindowSize(); List <Sample> aggRecordList = new List <Sample>(anomalySize); double[] likelihoods = new double[anomalySize]; int i = 0; foreach (Sample sample in anomalyScores) { MovingAverage.Calculation calc = MovingAverage.Compute(historicalValues, total, sample.score, windowSize); aggRecordList.Add( new Sample( sample.date, sample.value, calc.GetAverage())); total = calc.GetTotal(); likelihoods[i++] = NormalProbability(calc.GetAverage(), (Statistic)@params.Distribution()); } // Filter the likelihood values. First we prepend the historical likelihoods // to the current set. Then we filter the values. We peel off the likelihoods // to return and the last windowSize values to store for later. double[] likelihoods2 = ArrayUtils.Concat(histLikelihoods, likelihoods); double[] filteredLikelihoods = FilterLikelihoods(likelihoods2); likelihoods = Arrays.CopyOfRange(filteredLikelihoods, filteredLikelihoods.Length - likelihoods.Length, filteredLikelihoods.Length); double[] historicalLikelihoods = Arrays.CopyOf(likelihoods2, likelihoods2.Length - Math.Min(windowSize, likelihoods2.Length)); // Update the estimator Parameters newAnomalyParameters = Parameters.Empty(); newAnomalyParameters.SetParameterByKey(Parameters.KEY.ANOMALY_KEY_DIST, @params.Distribution()); newAnomalyParameters.SetParameterByKey(Parameters.KEY.ANOMALY_KEY_MVG_AVG, new MovingAverage(historicalValues, total, windowSize)); newAnomalyParameters.SetParameterByKey(Parameters.KEY.ANOMALY_KEY_HIST_LIKE, historicalLikelihoods); AnomalyParams newParams = new AnomalyParams(newAnomalyParameters); //AnomalyParams newParams = new AnomalyParams( // new string[] { "distribution", "movingAverage", "historicalLikelihoods" }, // @params.Distribution(), // new MovingAverage(historicalValues, total, windowSize), // historicalLikelihoods); return(new AnomalyLikelihoodMetrics( likelihoods, new AveragedAnomalyRecordList(aggRecordList, historicalValues, total), newParams)); }