R/GetDetectorScore_getWindowsLimits.R

Defines functions GetWindowsLimits

Documented in GetWindowsLimits

#' Get windows limits
#'
#' @description \code{GetWindowsLimits} Calculates the start and end positions of each window that
#' are focused on the real anomalies. This windows can be used to know if the detected anomaly is a
#' true positive or not.
#'
#' @param data All dataset with training and test datasets and with at least \code{timestamp},
#' \code{value} and \code{is.real.anomaly} columns.
#' @param windowLength Window length. See \code{\link{GetWindowLength}}.
#'
#' @details \code{data} must be a data.frame with  \code{timestamp}, \code{value}, \code{is.anomaly}
#' and \code{is.real.anomaly} columns. \code{timestamp} column can be numeric, of type POSIXct, or a
#' character type date convertible to POSIXct. \code{windowLength} must be numeric value.
#'
#' @return Same data set with two additional columns \code{start.limit} and \code{end.limit} where
#' for each is.real.anomaly equal to 1 is indicated the position in the data set where each window
#' starts and ends. If two anomalies fall within the same window, the start and end positions
#' are only indicated on the first of them.
#'
#' @references A. Lavin and S. Ahmad, “Evaluating Real-time Anomaly Detection Algorithms – the
#' Numenta Anomaly Benchmark,” in 14th International Conference on Machine Learning and
#' Applications (IEEE ICMLA’15), 2015.
#'
#' @example tests/examples/getWindowsLimits_example.R
#'
#' @export

GetWindowsLimits <- function(data, windowLength = NULL) {

  col.names <- names(data)
  n <- nrow(data)

  if (sum(c("timestamp", "value", "is.real.anomaly") %in% col.names) != 3 | n < 1) {
    stop("data argument must be a data.frame with timestamp, value and is.real.anomaly columns.")
  }

  if (!is.null(windowLength)) {
    if (!is.numeric(windowLength) | windowLength < 0) {
      stop("windowLength argument must be an integer.")
    }
  } else {
    if (sum(data$is.real.anomaly) == 0) {
      windowLength <- 0
    } else {
      windowLength <- GetWindowLength(n, sum(data$is.real.anomaly))
    }

  }

  Calculate.limits <- function(index) {
    start <- index - floor(windowLength / 2)
    end <- index + floor(windowLength / 2)
    if (start <= 0) {
      start <- index
    }
    if (end > nrow(data)) {
      end <- nrow(data)
    }
    return(c(start, end))
  }

  data$start.limit <- 0
  data$end.limit <- 0

  if(windowLength == 0) {
    return(data)
  }

  anomaly.index <- which(data$is.real.anomaly == 1)
  data[anomaly.index, c("start.limit", "end.limit")] <- t(sapply(anomaly.index, Calculate.limits))

  if (length(anomaly.index) > 1) {
    for (i in 2:length(anomaly.index)) {
      if (data[anomaly.index[i], "start.limit"] < data[(anomaly.index[i - 1]), "end.limit"]) {
        start <- data[anomaly.index[i - 1], "start.limit"]
        end <- data[anomaly.index[i], "end.limit"]
        data[anomaly.index[i - 1], c("start.limit", "end.limit")] <- c(start, end)
        data[anomaly.index[i], c("start.limit", "end.limit")] <- 0
      }
    }
  }

  return(data)

}

Try the otsad package in your browser

Any scripts or data that you put into this service are public.

otsad documentation built on Sept. 6, 2019, 5:02 p.m.