|
4 | 4 | # Copyright (c) 2023, 2024 Oracle and/or its affiliates. |
5 | 5 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ |
6 | 6 |
|
7 | | -import pandas as pd |
8 | | - |
9 | 7 | from ads.common.decorator.runtime_dependency import runtime_dependency |
10 | | - |
11 | | -from .base_model import AnomalyOperatorBaseModel |
12 | | -from .anomaly_dataset import AnomalyOutput |
13 | 8 | from ads.opctl.operator.lowcode.anomaly.const import OutputColumns |
| 9 | +from .anomaly_dataset import AnomalyOutput |
| 10 | +from .base_model import AnomalyOperatorBaseModel |
| 11 | +from ..const import SupportedModels |
| 12 | +from ads.opctl import logger |
14 | 13 |
|
15 | 14 |
|
16 | 15 | class AutoTSOperatorModel(AnomalyOperatorBaseModel): |
17 | 16 | """Class representing AutoTS Anomaly Detection operator model.""" |
| 17 | + model_mapping = { |
| 18 | + "isolationforest": "IsolationForest", |
| 19 | + "lof": "LOF", |
| 20 | + "ee": "EE", |
| 21 | + "zscore": "zscore", |
| 22 | + "rolling_zscore": "rolling_zscore", |
| 23 | + "mad": "mad", |
| 24 | + "minmax": "minmax", |
| 25 | + "iqr": "IQR" |
| 26 | + } |
18 | 27 |
|
19 | 28 | @runtime_dependency( |
20 | 29 | module="autots", |
21 | 30 | err_msg=( |
22 | | - "Please run `pip3 install autots` to " |
23 | | - "install the required dependencies for AutoTS." |
| 31 | + "Please run `pip3 install autots` to " |
| 32 | + "install the required dependencies for AutoTS." |
24 | 33 | ), |
25 | 34 | ) |
26 | 35 | def _build_model(self) -> AnomalyOutput: |
27 | 36 | from autots.evaluator.anomaly_detector import AnomalyDetector |
28 | 37 |
|
29 | | - method = self.spec.model_kwargs.get("method") |
30 | | - transform_dict = self.spec.model_kwargs.get("transform_dict", {}) |
31 | | - |
32 | | - if method == "random" or method == "deep" or method == "fast": |
33 | | - new_params = AnomalyDetector.get_new_params(method=method) |
34 | | - transform_dict = new_params.pop("transform_dict") |
35 | | - |
36 | | - for key, value in new_params.items(): |
37 | | - self.spec.model_kwargs[key] = value |
38 | | - |
39 | | - if self.spec.model_kwargs.get("output") is None: |
40 | | - self.spec.model_kwargs["output"] = "univariate" |
41 | | - |
42 | | - if "transform_dict" not in self.spec.model_kwargs: |
43 | | - self.spec.model_kwargs["transform_dict"] = transform_dict |
44 | | - |
45 | | - if self.spec.contamination != 0.1: # TODO: remove hard-coding |
46 | | - self.spec.model_kwargs.get("method_params", {})[ |
47 | | - "contamination" |
48 | | - ] = self.spec.contamination |
49 | | - |
50 | | - model = AnomalyDetector(**self.spec.model_kwargs) |
| 38 | + method = SupportedModels.ISOLATIONFOREST if self.spec.model == SupportedModels.AutoTS else self.spec.model |
| 39 | + model_params = {"method": self.model_mapping[method], |
| 40 | + "transform_dict": self.spec.model_kwargs.get("transform_dict", {}), |
| 41 | + "output": self.spec.model_kwargs.get("output", "univariate"), "method_params": {}} |
| 42 | + # Supported methods with contamination param |
| 43 | + if method in [SupportedModels.ISOLATIONFOREST, SupportedModels.LOF, SupportedModels.EE]: |
| 44 | + model_params["method_params"][ |
| 45 | + "contamination"] = self.spec.contamination if self.spec.contamination else 0.01 |
| 46 | + else: |
| 47 | + if self.spec.contamination: |
| 48 | + raise ValueError(f"The contamination parameter is not supported for the selected model \"{method}\"") |
| 49 | + logger.info(f"model params: {model_params}") |
| 50 | + |
| 51 | + model = AnomalyDetector(**model_params) |
51 | 52 |
|
52 | 53 | date_column = self.spec.datetime_column.name |
53 | 54 |
|
54 | 55 | anomaly_output = AnomalyOutput(date_column=date_column) |
55 | 56 |
|
56 | 57 | for target, df in self.datasets.full_data_dict.items(): |
57 | 58 | data = df.set_index(date_column) |
58 | | - |
59 | 59 | (anomaly, score) = model.detect(data) |
60 | | - |
61 | 60 | if len(anomaly.columns) == 1: |
62 | 61 | score.rename( |
63 | 62 | columns={score.columns.values[0]: OutputColumns.SCORE_COL}, |
64 | 63 | inplace=True, |
65 | 64 | ) |
66 | 65 | score = 1 - score |
67 | 66 | score = score.reset_index(drop=False) |
68 | | - |
69 | 67 | col = anomaly.columns.values[0] |
70 | 68 | anomaly[col] = anomaly[col].replace({1: 0, -1: 1}) |
71 | 69 | anomaly.rename(columns={col: OutputColumns.ANOMALY_COL}, inplace=True) |
72 | 70 | anomaly = anomaly.reset_index(drop=False) |
73 | | - |
74 | 71 | anomaly_output.add_output(target, anomaly, score) |
75 | | - |
76 | 72 | else: |
77 | 73 | raise NotImplementedError( |
78 | 74 | "Multi-Output Anomaly Detection is not yet supported in autots" |
79 | 75 | ) |
80 | | - |
81 | 76 | return anomaly_output |
82 | 77 |
|
83 | 78 | def _generate_report(self): |
|
0 commit comments