Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions ads/model/model_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ class Framework(ExtendedEnum):
PYOD = "pyod"
SPACY = "spacy"
PROPHET = "prophet"
THETA = "theta"
ETSForecaster = "ets"
SKTIME = "sktime"
STATSMODELS = "statsmodels"
CUML = "cuml"
Expand Down
61 changes: 61 additions & 0 deletions ads/opctl/operator/lowcode/common/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
InvalidParameterError,
)
from ads.secrets import ADBSecretKeeper
from sktime.param_est.seasonality import SeasonalityACF


def call_pandas_fsspec(pd_fn, filename, storage_options, **kwargs):
Expand Down Expand Up @@ -385,3 +386,63 @@ def enable_print():
except Exception:
pass
sys.stdout = sys.__stdout__


def find_seasonal_period_from_dataset(data: pd.DataFrame) -> tuple[int, list]:
try:
sp_est = SeasonalityACF()
sp_est.fit(data)
sp = sp_est.get_fitted_params()["sp"]
probable_sps = sp_est.get_fitted_params()["sp_significant"]
return sp, probable_sps
except Exception as e:
logger.warning(f"Unable to find seasonal period: {e}")
return None, None


def normalize_frequency(freq: str) -> str:
"""
Normalize pandas frequency strings to sktime/period-compatible formats.

Args:
freq: Pandas frequency string

Returns:
Normalized frequency string compatible with PeriodIndex
"""
if freq is None:
return None

freq = freq.upper()

# Handle weekly frequencies with day anchors (W-SUN, W-MON, etc.)
if freq.startswith("W-"):
return "W"

# Handle month start/end frequencies
freq_mapping = {
"MS": "M", # Month Start -> Month End
"ME": "M", # Month End -> Month
"BMS": "M", # Business Month Start -> Month
"BME": "M", # Business Month End -> Month
"QS": "Q", # Quarter Start -> Quarter
"QE": "Q", # Quarter End -> Quarter
"BQS": "Q", # Business Quarter Start -> Quarter
"BQE": "Q", # Business Quarter End -> Quarter
"YS": "Y", # Year Start -> Year (Alias: A)
"AS": "Y", # Year Start -> Year (Alias: A)
"YE": "Y", # Year End -> Year
"AE": "Y", # Year End -> Year
"BYS": "Y", # Business Year Start -> Year
"BAS": "Y", # Business Year Start -> Year
"BYE": "Y", # Business Year End -> Year
"BAE": "Y", # Business Year End -> Year
}

# Handle frequencies with prefixes (e.g., "2W", "3M")
for old_freq, new_freq in freq_mapping.items():
if freq.endswith(old_freq):
prefix = freq[:-len(old_freq)]
return f"{prefix}{new_freq}" if prefix else new_freq

return freq
2 changes: 2 additions & 0 deletions ads/opctl/operator/lowcode/forecast/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ class SupportedModels(ExtendedEnum):
NeuralProphet = "neuralprophet"
LGBForecast = "lgbforecast"
AutoMLX = "automlx"
Theta = "theta"
ETSForecaster = "ets"
AutoTS = "autots"
# Auto = "auto"

Expand Down
35 changes: 35 additions & 0 deletions ads/opctl/operator/lowcode/forecast/model/base_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -962,3 +962,38 @@ def _get_unique_filename(self, base_path: str, storage_options: dict = None) ->
f"Error checking OCI path existence: {e}. Using original path."
)
return base_path

def generate_explanation_report_from_data(self) -> tuple[rc.Block, rc.Block]:
if not self.target_cat_col:
self.formatted_global_explanation = (
self.formatted_global_explanation.rename(
{"Series 1": self.original_target_column},
axis=1,
)
)
self.formatted_local_explanation.drop(
"Series", axis=1, inplace=True
)

# Create a markdown section for the global explainability
global_explanation_section = rc.Block(
rc.Heading("Global Explainability", level=2),
rc.Text(
"The following tables provide the feature attribution for the global explainability."
),
rc.DataTable(self.formatted_global_explanation, index=True),
)

blocks = [
rc.DataTable(
local_ex_df.drop("Series", axis=1),
label=s_id if self.target_cat_col else None,
index=True,
)
for s_id, local_ex_df in self.local_explanation.items()
]
local_explanation_section = rc.Block(
rc.Heading("Local Explanation of Models", level=2),
rc.Select(blocks=blocks) if len(blocks) > 1 else blocks[0],
)
return global_explanation_section, local_explanation_section
Loading
Loading