Example #1
0
class AveragePostprocessor(BasePostprocessor):
    """A postprocessor that convert a score to the average of of all previous scores.
    """

    def __init__(self):
        self.meter = AverageMeter()

    def fit_partial(self, score):
        """Fits the postprocessor to the (next) timestep's score.

        Args:
            score (float): Input score.

        Returns:
            object: self.
        """

        self.meter.update(score)

        return self

    def transform_partial(self, score=None):
        """Gets the current average. This method should be used immediately after the fit_partial method with same score.

        Args:
            score (float): The input score.

        Returns:
            float: Transformed score.
        """
        return self.meter.get()
Example #2
0
class ZScorePostprocessor(BasePostprocessor):
    """A postprocessor that normalize the score via Z-score normalization.
    """

    def __init__(self):
        self.variance_meter = VarianceMeter()
        self.average_meter = AverageMeter()

    def fit_partial(self, score):
        """Fits the postprocessor to the (next) timestep's score.

        Args:
            score (float): Input score.

        Returns:
            object: self.
        """
        self.variance_meter.update(score)
        self.average_meter.update(score)

        return self

    def transform_partial(self, score):
        """Applies postprocessing to the score.

        Args:
            score (float): The input score.

        Returns:
            float: Transformed score.
        """
        zscore = (score - self.average_meter.get()) / \
            np.sqrt(self.variance_meter.get())

        return zscore
Example #3
0
class GaussianTailProbabilityCalibrator(BasePostprocessor):
    """Assuming that the scores follow normal distribution, this class provides an interface to convert the scores into probabilities via Q-function, i.e., the tail function of Gaussian distribution :cite:`ahmad2017unsupervised`.

        Args:
            running_statistics (bool): Whether to calculate the mean and variance through running window. The window size is defined by the `window_size` parameter.
            window_size (int): The size of window for running average and std. Ignored if `running_statistics` parameter is False.
    """
    def __init__(self, running_statistics=True, window_size=6400):
        self.running_statistics = running_statistics
        self.window_size = window_size

        if self.running_statistics:
            self.avg_meter = RunningStatistic(AverageMeter, self.window_size)
            self.var_meter = RunningStatistic(VarianceMeter, self.window_size)
        else:
            self.avg_meter = AverageMeter()
            self.var_meter = RunningStatistic(VarianceMeter, self.window_size)

    def fit_partial(self, score):
        """Fits particular (next) timestep's score to train the postprocessor.

        Args:
            score (float): Input score.
        Returns:
            object: self.
        """
        self.avg_meter.update(score)
        self.var_meter.update(score)

        return self

    def transform_partial(self, score):
        """Transforms given score.

        Args:
            score (float): Input score.

        Returns:
            float: Processed score.
        """
        mean = self.avg_meter.get()
        var = self.var_meter.get()
        if var > 0:
            std = np.sqrt(var)
        else:
            std = 1.0

        return 1 - self._qfunction(score, mean, std)

    def _qfunction(self, x, mean, std):
        """
        Given the normal distribution specified by the mean and standard deviation args, return the probability of getting samples > x. Implementation is adapted from the https://github.com/ish-vlad/Conformal-Anomaly-Detection/blob/22769b8d3cede7fabd978a36cdd2853255e450ac/scripts/nab_module/nab/detectors/gaussian/windowedGaussian_detector.py This is the
        Q-function: the tail probability of the normal distribution.
        """

        # Calculate the Q function with the complementary error function, explained
        # here:
        # http://www.gaussianwaves.com/2012/07/q-function-and-error-functions
        z = (x - mean) / std
        return 0.5 * math.erfc(z / math.sqrt(2))
Example #4
0
    def __init__(self, running_statistics=True, window_size=6400):
        self.running_statistics = running_statistics
        self.window_size = window_size

        if self.running_statistics:
            self.avg_meter = RunningStatistic(AverageMeter, self.window_size)
            self.var_meter = RunningStatistic(VarianceMeter, self.window_size)
        else:
            self.avg_meter = AverageMeter()
            self.var_meter = RunningStatistic(VarianceMeter, self.window_size)
    def __init__(self, substracted_statistic="mean", absolute=True):
        self.absolute = absolute
        self.variance_meter = VarianceMeter()

        if substracted_statistic == "median":
            self.sub_meter = MedianMeter()
        elif substracted_statistic == "mean":
            self.sub_meter = AverageMeter()
        else:
            raise ValueError(
                "Unknown substracted_statistic value! Please choose median or mean."
            )
class StandardAbsoluteDeviation(BaseModel):
    """The model that assigns the deviation from the mean (or median) and divides with the standard deviation. This model is based on the 3-Sigma rule described in :cite:`hochenbaum2017automatic`.

        substracted_statistic (str): The statistic to be substracted for scoring. It is either "mean" or "median". (Default="mean").
        absolute (bool): Whether to output score's absolute value. (Default=True).
    """
    def __init__(self, substracted_statistic="mean", absolute=True):
        self.absolute = absolute
        self.variance_meter = VarianceMeter()

        if substracted_statistic == "median":
            self.sub_meter = MedianMeter()
        elif substracted_statistic == "mean":
            self.sub_meter = AverageMeter()
        else:
            raise ValueError(
                "Unknown substracted_statistic value! Please choose median or mean."
            )

    def fit_partial(self, X, y=None):
        """Fits the model to next instance.

        Args:
            X (np.float array of shape (1,)): The instance to fit. Note that this model is univariate.
            y (int): Ignored since the model is unsupervised (Default=None).

        Returns:
            object: Returns the self.
        """
        assert len(X) == 1  # Only for time series

        self.variance_meter.update(X)
        self.sub_meter.update(X)

        return self

    def score_partial(self, X):
        """Scores the anomalousness of the next instance.

        Args:
            X (np.float array of shape (1,)): The instance to score. Higher scores represent more anomalous instances whereas lower scores correspond to more normal instances.

        Returns:
            float: The anomalousness score of the input instance.
        """
        sub = self.sub_meter.get()
        dev = self.variance_meter.get()**0.5

        score = (X - sub) / (dev + 1e-10)

        return abs(score) if self.absolute else score
Example #7
0
    def __init__(
            self,
            metric_cls,
            window_size,
            ignore_nonempty_last=True,
            **kwargs):
        super().__init__()
        self.ignore_nonempty_last = ignore_nonempty_last
        self.window_size = window_size
        self.metric_cls = metric_cls

        self.metric = self._init_metric(**kwargs)

        self.score_meter = AverageMeter()
        self.step = 0
        self.num_windows = 1
Example #8
0
class WindowedMetric(BaseMetric):
    """A helper class to evaluate windowed metrics. The distributions of the streaming model scores often change due to model collapse (i.e. becoming closer to the always loss=0) or appearing nonstationarities. Thus, the metrics such as ROC or AUC scores may change drastically. To prevent their effect, this class creates windows of size `window_size`. After each `window_size`th object, a new instance of the `metric_cls` is being created. Lastly, the metrics from all windows are averaged :cite:`xstream,gokcesu2017online`.

    Args:
        metric_cls (class): The metric class to be windowed.
        window_size (int): The window size.
        ignore_nonempty_last (bool): Whether to ignore the score of the nonempty last window. Note that the empty last window is always ignored.
    """

    def __init__(
            self,
            metric_cls,
            window_size,
            ignore_nonempty_last=True,
            **kwargs):
        super().__init__()
        self.ignore_nonempty_last = ignore_nonempty_last
        self.window_size = window_size
        self.metric_cls = metric_cls

        self.metric = self._init_metric(**kwargs)

        self.score_meter = AverageMeter()
        self.step = 0
        self.num_windows = 1

    def _init_metric(self, **kwargs):

        return self.metric_cls(**kwargs)

    def update(self, y_true, y_pred):
        """Updates the score with new true label and predicted score/label.

        Args:
            y_true : float
                The ground truth score for the incoming instance.
            y_pred : float
                The predicted score for the incoming instance.

        Returns:
            object: self.
        """
        self.step += 1
        self.metric.update(y_true, y_pred)

        if self.step % self.window_size == 0:
            self.num_windows += 1
            score = self.metric.get()
            self.score_meter.update(score)
            self.metric = self._init_metric()

        return self

    def get(self):
        """Obtains the averaged score.

        Returns:
            float: The average score of the windows.
        """
        if self.num_windows == 1:
            return self.metric.get()
        elif not self.ignore_nonempty_last and self.step % self.window_size != 0:
            return (self.metric.get() + self.score_meter.get() * (self.num_windows - 1)) / self.num_windows
        else:
            return self.score_meter.get()
Example #9
0
 def __init__(self):
     self.meter = AverageMeter()
Example #10
0
 def __init__(self):
     self.variance_meter = VarianceMeter()
     self.average_meter = AverageMeter()