def test_slack_single_anomaly_combine2_min_gap_modify(self): intersect = Slack('test') intersect.set_param_value('slack', 0) intersect.set_param_value('min_span', '') intersect.set_param_value('min_gap', '2') fst = [Anomaly.from_epoch(1, 3), Anomaly.from_epoch(3, 4)] snd = [] expected_anomalies = [{ 'id': '4df66ed193a28317221ac37f78d0d7dc', 'from': 1000, 'to': 4000, 'duration': 3, 'score': 1.0, 'source_anomalies': [ '907118cc03fec0a8d2c575b1954afdc4', '2258259e7e550cbe14d3f31b2172e150' ], 'source_node': 'test', }] expected_debug = { 'anomaly_count_diff': -1, 'end_anomaly_count': 1, 'start_anomaly_count': 2 } self.case(intersect, fst, snd, expected_anomalies, expected_debug)
def test_slack_single_anomaly_combine2_min_gap_no_modify(self): intersect = Slack('test') intersect.set_param_value('slack', 0) intersect.set_param_value('min_span', '') intersect.set_param_value('min_gap', '2') fst = [Anomaly.from_epoch(1, 3), Anomaly.from_epoch(5, 7)] snd = [] expected_anomalies = [{ 'id': '907118cc03fec0a8d2c575b1954afdc4', 'from': 1000, 'to': 3000, 'duration': 2, 'score': 1.0, 'source_anomalies': [], 'source_node': 'fst', }, { 'id': '39b7611a1843441315cda0b35edd070a', 'from': 5000, 'to': 7000, 'duration': 2, 'score': 1.0, 'source_anomalies': [], 'source_node': 'fst', }] expected_debug = { 'anomaly_count_diff': 0, 'end_anomaly_count': 2, 'start_anomaly_count': 2 } self.case(intersect, fst, snd, expected_anomalies, expected_debug)
def test_slack_single_anomaly_min_span_combine_same(self): intersect = Slack('test') intersect.set_param_value('slack', 0) intersect.set_param_value('min_span', '4') intersect.set_param_value('min_gap', '') fst = [Anomaly.from_epoch(1, 3), Anomaly.from_epoch(3, 5)] snd = [] expected_anomalies = [{ 'id': 'c3a73aa49c1e4c20b0fbed653cf17538', 'from': 0, 'to': 6000, 'duration': 6, 'score': 1.0, 'source_anomalies': [ '907118cc03fec0a8d2c575b1954afdc4', '1ee724e9a7a81b6036caa98a0928be3b' ], 'source_node': 'test', }] expected_debug = { 'anomaly_count_diff': -1, 'end_anomaly_count': 1, 'start_anomaly_count': 2 } self.case(intersect, fst, snd, expected_anomalies, expected_debug)
def test_slack_single_anomaly_min_span_combine_diff(self): intersect = Slack('test') intersect.set_param_value('slack', 0) intersect.set_param_value('min_span', '4') intersect.set_param_value('min_gap', '') fst = [Anomaly.from_epoch(1, 3)] snd = [Anomaly.from_epoch(3, 5)] expected_anomalies = [{ 'id': 'fdccae96bcc19b9b66343b183196a132', 'from': 0, 'to': 6000, 'duration': 6, 'score': 1.0, 'source_anomalies': [ '907118cc03fec0a8d2c575b1954afdc4', '00a3ef8b7bacb638bd304696a563e771' ], 'source_node': 'test', }] expected_debug = { 'anomaly_count_diff': -1, 'end_anomaly_count': 1, 'start_anomaly_count': 2 } self.case(intersect, fst, snd, expected_anomalies, expected_debug)
def test_ordering(self): a1 = Anomaly.from_epoch(1, 2, 1.0) a2 = Anomaly.from_epoch(1, 3, 1.0) a3 = Anomaly.from_epoch(3, 4, 1.0) a4 = Anomaly.from_epoch(4, 5, 1.0) anomalies = [a3, a4, a2, a1] self.assertEqual([a1, a2, a3, a4], sorted(anomalies))
def anomalies_from_mock_series(series): anomalies = [] if series.span() > 0: if series.pdseries[0] == 1: start = series.start else: start = None last = series.start for t, val in series.pdseries.items(): if val == 1 and start is None: start = t if val == 0 and start is not None: anomalies.append(Anomaly(start, last, 1.0)) start = None last = t if start is not None: anomalies.append(Anomaly(start, series.end, 1.0)) for anomaly in anomalies: anomaly.set_source_node(Node('mock_node')) return anomalies
def test_overlap(self): anomalies = [ Anomaly.from_epoch(1, 4), Anomaly.from_epoch(3, 6) ] anomalies = sorted(anomalies) self.assertRaises(Exception, cb.assert_no_overlap, anomalies)
def test_no_overlap(self): anomalies = [ Anomaly.from_epoch(1, 2), Anomaly.from_epoch(2, 6) ] anomalies = sorted(anomalies) cb.assert_no_overlap(anomalies)
def test_intersect_aggregator_temporal_some_overlap_pair_case4(self): intersect = Intersect('test') intersect.set_param_value('resolution', 'temporal') fst = [Anomaly.from_epoch(1, 3)] snd = [Anomaly.from_epoch(0, 4)] expected = [(1, 3)] self.case_temporal(intersect, fst, snd, expected)
def test_slack_single_anomaly_min_span_combine_repeated_same_start_end( self): intersect = Slack('test') intersect.set_param_value('slack', 0) intersect.set_param_value('min_span', '4') intersect.set_param_value('min_gap', '') fst = [Anomaly.from_epoch(1, 3), Anomaly.from_epoch(1, 3)] snd = [] expected_anomalies = [{ 'id': 'c386a8dcb491be05ee22d597a568c6c5', 'from': 0, 'to': 4000, 'duration': 4, 'score': 1.0, 'source_anomalies': ['907118cc03fec0a8d2c575b1954afdc4'], 'source_node': 'test', }] expected_debug = { 'anomaly_count_diff': -1, 'end_anomaly_count': 1, 'start_anomaly_count': 2 } self.case(intersect, fst, snd, expected_anomalies, expected_debug)
def test_slack_single_anomaly_min_span_combine_repeated_same_end(self): intersect = Slack('test') intersect.set_param_value('slack', 0) intersect.set_param_value('min_span', '') intersect.set_param_value('min_gap', '') fst = [Anomaly.from_epoch(1, 3), Anomaly.from_epoch(2, 3)] snd = [] expected_anomalies = [{ 'id': '38d8163446902c87895ce84636452da2', 'from': 1000, 'to': 3000, 'duration': 2, 'score': 1.0, 'source_anomalies': [ '907118cc03fec0a8d2c575b1954afdc4', '3c7002f0fd6171fa486fb34a853becac' ], 'source_node': 'test', }] expected_debug = { 'anomaly_count_diff': -1, 'end_anomaly_count': 1, 'start_anomaly_count': 2 } self.case(intersect, fst, snd, expected_anomalies, expected_debug)
def test_intersect_aggregator_anomaly_wise_some_overlap_non_strict(self): intersect = Intersect('test') intersect.set_param_value('resolution', 'anomaly') intersect.set_param_value('strict', False) a1 = Anomaly.from_epoch(0, 2) a2 = Anomaly.from_epoch(1, 3) expected = [a1, a2] self.case_anomaly_wise(intersect, [a1], [a2], expected)
def test_intersect_aggregator_anomaly_wise_some_overlap_strict(self): intersect = Intersect('test') intersect.set_param_value('resolution', 'anomaly') intersect.set_param_value('strict', True) fst = [Anomaly.from_epoch(0, 2)] snd = [Anomaly.from_epoch(1, 3)] expected = [] self.case_anomaly_wise(intersect, fst, snd, expected)
def test_set_elements(self): a1 = Anomaly.from_epoch(1, 2, 1.0) a2 = Anomaly.from_epoch(1, 2, 1.0) a3 = Anomaly.from_epoch(2, 3, 1.0) a4 = Anomaly.from_epoch(3, 4, 1.0) s = set([a1, a3]) self.assertTrue(a1 in s) self.assertTrue(a2 in s) self.assertTrue(a3 in s) self.assertFalse(a4 in s)
def test_intersect_aggregator_anomaly_wise_full_overlap(self): intersect = Intersect('test') intersect.set_param_value('resolution', 'anomaly') intersect.set_param_value('strict', False) a1 = Anomaly.from_epoch(0, 5) a2 = Anomaly.from_epoch(2, 5) a3 = Anomaly.from_epoch(2, 6) fst = [a1] snd = [a2, a3] expected = fst + snd self.case_anomaly_wise(intersect, fst, snd, expected)
def test_metrics_case1(self): test_series = Series.from_array([[0, 0], [1, 1], [2, 0], [3, 0], [4, 0], [5, 1], [6, 1], [7, 0]]) actual_anomalies = [ Anomaly.from_epoch(1, 1), Anomaly.from_epoch(2, 2), Anomaly.from_epoch(4, 4) ] analyzer = MockAnalyzer(actual_anomalies) expected_anomalies = TestCase.anomalies_from_mock_series(test_series) expected_analysis = Analysis(test_series, None, expected_anomalies, False) test = TestCase("testcase1", test_series, analyzer, expected_analysis) result = test.run() anomaly_metrics = result.anomaly_metrics expected_tp = mcb.epochs_to_timestamp([1]) expected_fp = mcb.epochs_to_timestamp([2, 4]) expected_tn = mcb.epochs_to_timestamp([0, 3, 7]) expected_fn = mcb.epochs_to_timestamp([5, 6]) self.assertEqual(expected_tp, anomaly_metrics.tp) self.assertEqual(expected_fp, anomaly_metrics.fp) self.assertEqual(expected_tn, anomaly_metrics.tn) self.assertEqual(expected_fn, anomaly_metrics.fn) self.assertEqual(1, anomaly_metrics.tp_count()) self.assertEqual(2, anomaly_metrics.fp_count()) self.assertEqual(2, anomaly_metrics.fn_count()) self.assertEqual(3, anomaly_metrics.tn_count()) expected_tp_ranges = mcb.epochs_to_ranges([[1, 2]]) expected_fp_ranges = mcb.epochs_to_ranges([[2, 3], [4, 5]]) expected_fn_ranges = mcb.epochs_to_ranges([[5, 7]]) self.assertEqual(expected_tp_ranges, anomaly_metrics.tp_ranges) self.assertEqual(expected_fp_ranges, anomaly_metrics.fp_ranges) self.assertEqual(expected_fn_ranges, anomaly_metrics.fn_ranges) self.assertAlmostEqual(0.33, anomaly_metrics.precision(), 2) self.assertAlmostEqual(0.33, anomaly_metrics.recall(), 2) self.assertAlmostEqual(0.33, anomaly_metrics.f1(), 2)
def test_output_format(self): all_ids = [ 'e4faf6ec4da15ed9a37f75d7bcc55d12', 'cb1eda751f67ae1b5d0ae2bd69f20531', '5e1160651d9bf60d7136c193530e4c12', '9ab7768778c2eafba90943ca14e2b970', '0d78b95e849701520c5b38d7cbdecf58', ] self.assertEqual(len(all_ids), len(np.unique(all_ids))) self.output_format_case(1, 2, 1.0, 'test_node', [], { 'id': all_ids.pop(), 'from': 1000, 'to': 2000, 'duration': 1.0, 'score': 1.0, 'source_anomalies': [], 'source_node': 'test_node' }) self.output_format_case(1, 1, 1.0, 'test_node', [], { 'id': all_ids.pop(), 'from': 1000, 'to': 1000, 'duration': 0.0, 'score': 1.0, 'source_anomalies': [], 'source_node': 'test_node' }) self.output_format_case(1, 2, 0.0, 'test_node', [], { 'id': all_ids.pop(), 'from': 1000, 'to': 2000, 'duration': 1.0, 'score': 0.0, 'source_anomalies': [], 'source_node': 'test_node' }) self.output_format_case(1, 2, 1.0, 'other_node', [], { 'id': all_ids.pop(), 'from': 1000, 'to': 2000, 'duration': 1.0, 'score': 1.0, 'source_anomalies': [], 'source_node': 'other_node' }) source_anomaly = Anomaly.from_epoch(1, 2, 1.0) source_anomaly.set_source_node(Node('other_node')) self.output_format_case(1, 2, 1.0, 'test_node', [source_anomaly], { 'id': all_ids.pop(), 'from': 1000, 'to': 2000, 'duration': 1.0, 'score': 1.0, 'source_anomalies': ['cb1eda751f67ae1b5d0ae2bd69f20531'], 'source_node': 'test_node' })
def test_copy(self): a = Anomaly.from_epoch(1, 2, 1.0) b = a.copy() self.assertEqual(a, b) self.assertEqual('132fe9c5a03d96f6b80b7484f87e3052', a.id()) self.assertEqual(a.id(), b.id()) b.set_source_anomalies([a]) self.assertEqual('dd5ef91f83a839b68b8a456b01eb45fe', b.id()) self.assertNotEqual(a.id(), b.id()) self.assertNotEqual(a, b)
def test_slack_single_anomaly_min_span_does_not_combine(self): intersect = Slack('test') intersect.set_param_value('slack', 0) intersect.set_param_value('min_span', '4') intersect.set_param_value('min_gap', '') fst = [Anomaly.from_epoch(1, 3), Anomaly.from_epoch(10, 20)] snd = [] expected_anomalies = [{ 'id': 'c386a8dcb491be05ee22d597a568c6c5', 'from': 0, 'to': 4000, 'duration': 4, 'score': 1.0, 'source_anomalies': ['907118cc03fec0a8d2c575b1954afdc4'], 'source_node': 'test', }, { 'id': '3548387b8640052ccbcfc8f0fb4438e3', 'from': 10000, 'to': 20000, 'duration': 10, 'score': 1.0, 'source_anomalies': [], 'source_node': 'fst', }] expected_debug = { 'anomaly_count_diff': 0, 'end_anomaly_count': 2, 'start_anomaly_count': 2 } self.case(intersect, fst, snd, expected_anomalies, expected_debug)
def test_slack_single_anomaly_min_span_combine3_same_modify(self): intersect = Slack('test') intersect.set_param_value('slack', 0) intersect.set_param_value('min_span', '') intersect.set_param_value('min_gap', '') fst = [ Anomaly.from_epoch(1, 3), Anomaly.from_epoch(2, 4), Anomaly.from_epoch(3, 5) ] snd = [] expected_anomalies = [{ 'id': '6ce5c127caf55b9c597b8a7df7253587', 'from': 1000, 'to': 5000, 'duration': 4, 'score': 1.0, 'source_anomalies': [ '907118cc03fec0a8d2c575b1954afdc4', 'fae6500ecb59c1e6919c7ed915e3c9ea', '1ee724e9a7a81b6036caa98a0928be3b' ], 'source_node': 'test', }] expected_debug = { 'anomaly_count_diff': -2, 'end_anomaly_count': 1, 'start_anomaly_count': 3 } self.case(intersect, fst, snd, expected_anomalies, expected_debug)
def test_slack_edge_case_identity(self): intersect = Slack('test') intersect.set_param_value('slack', 0) intersect.set_param_value('min_span', '') fst = [Anomaly.from_epoch(1, 3)] snd = [] expected_anomalies = [{ 'id': '907118cc03fec0a8d2c575b1954afdc4', 'from': 1000, 'to': 3000, 'duration': 2, 'score': 1.0, 'source_anomalies': [], 'source_node': 'fst', }] expected_debug = { 'anomaly_count_diff': 0, 'end_anomaly_count': 1, 'start_anomaly_count': 1 } self.case(intersect, fst, snd, expected_anomalies, expected_debug)
def output_format_case(self, start, end, score, source_node_id, source_anomalies, expected): anomaly = Anomaly.from_epoch(start, end, score) anomaly.set_source_node(Node(source_node_id)) anomaly.set_source_anomalies(source_anomalies) self.assertEqual(expected, anomaly.output_format())
def test_union_aggregator_base_case(self): fst = [Anomaly.from_epoch(0, 1)] snd = [Anomaly.from_epoch(2, 4)] expected = fst + snd self.case_anomaly_wise(Union('test'), fst, snd, expected)
def test_inequality(self): a = Anomaly.from_epoch(1, 2, 1.0) b = Anomaly.from_epoch(2, 3, 1.0) self.assertNotEqual(a, b) self.assertNotEqual(hash(a), hash(b))
def test_epoch_span(self): anomaly = Anomaly.from_epoch(1, 2, 1.0) self.assertEqual((1, 2), anomaly.epoch_span_secs())