def _PassesThresholds( values, split_index, min_segment_size, min_absolute_change, min_relative_change, min_steppiness, multiple_of_std_dev): """Checks whether a point in a series appears to be an change point. Args: values: A list of numbers. split_index: An index in the list of numbers. min_segment_size: Threshold for size of segments before or after a point. min_absolute_change: Minimum absolute median change threshold. min_relative_change: Minimum relative median change threshold. min_steppiness: Threshold for how similar to a step a change point must be. multiple_of_std_dev: Threshold for change as multiple of std. deviation. Returns: True if it passes all of the thresholds, False otherwise. """ left, right = values[:split_index], values[split_index:] left_median, right_median = math_utils.Median(left), math_utils.Median(right) # 1. Segment size filter. if len(left) < min_segment_size or len(right) < min_segment_size: return False # 2. Absolute change filter. absolute_change = abs(left_median - right_median) if absolute_change < min_absolute_change: return False # 3. Relative change filter. relative_change = _RelativeChange(left_median, right_median) if relative_change < min_relative_change: return False # 4. Multiple of standard deviation filter. # The left and right sides are independently normalized so that their medians # are zero, then the two sides are concatenated together. This, in effect, # removes the step so that the step itself doesn't affect the std. dev. min_std_dev = min( math_utils.StandardDeviation(left), math_utils.StandardDeviation(right)) if absolute_change < multiple_of_std_dev * min_std_dev: return False # 5. Steppiness filter. steppiness = find_step.Steppiness(values, split_index) if steppiness < min_steppiness: return False # Passed all filters! return True
def _PassesThresholds(values, split_index, min_segment_size, min_absolute_change, min_relative_change, min_steppiness, multiple_of_std_dev): """Checks whether a point in a series appears to be an change point. Args: values: A list of numbers. split_index: An index in the list of numbers. min_segment_size: Threshold for size of segments before or after a point. min_absolute_change: Minimum absolute median change threshold. min_relative_change: Minimum relative median change threshold. min_steppiness: Threshold for how similar to a step a change point must be. multiple_of_std_dev: Threshold for change as multiple of std. deviation. Returns: A tuple of (bool, string) where the bool indicates whether the split index passes the thresholds and the string being the reason it did not. """ left, right = values[:split_index], values[split_index:] left_median, right_median = math_utils.Median(left), math_utils.Median( right) # 1. Segment size filter. if len(left) < min_segment_size or len(right) < min_segment_size: return (False, 'min_segment_size') # 2. Absolute change filter. absolute_change = abs(left_median - right_median) if absolute_change < min_absolute_change: return (False, 'min_absolute_change') # 3. Relative change filter. relative_change = math_utils.RelativeChange(left_median, right_median) if relative_change < min_relative_change: return (False, 'min_relative_change') # 4. Multiple of standard deviation filter. min_std_dev = min(math_utils.StandardDeviation(left), math_utils.StandardDeviation(right)) if absolute_change < multiple_of_std_dev * min_std_dev: return (False, 'min_std_dev') # 5. Steppiness filter. steppiness = find_step.Steppiness(values, split_index) if steppiness < min_steppiness: return (False, 'min_steppiness') # Passed all filters! return (True, 'passed')
def testSteppiness_UpDownPattern_ReturnsZero(self): step = [1, 0, 1, 0, 1, 0, 1, 0] self.assertAlmostEqual(0.0, find_step.Steppiness(step, 4))
def testSteppiness_LengthOfSeriesDoesntAffectScore(self): step = [1, 2, 1, 2, 4, 3, 5, 4] step_long = [1, 2, 1, 2, 2, 1, 2, 1, 4, 3, 5, 4, 5, 3, 4, 4] self.assertAlmostEqual( find_step.Steppiness(step, 4), find_step.Steppiness(step_long, 8))
def testSteppiness_ImperfectStep_ReturnsValueBetweenZeroAndOne(self): step = [1, 2, 1, 2, 4, 3, 5, 4] self.assertAlmostEqual(0.56005865, find_step.Steppiness(step, 4))
def testSteppiness_PerfectStep_ReturnsOne(self): step = [3, 3, 3, 3, 10, 10, 10] self.assertEqual(1.0, find_step.Steppiness(step, 4))