Skip to content

Commit

Permalink
support of seasonalities as list of string
Browse files Browse the repository at this point in the history
Summary:
Currently, prophet defines a custom enum for seasonalities. There is no proper way to expose this enum to configerator to validate seasonality param at authoring time.

We can add a new thrift structure, but it will add maintenance overhead as we need to keep mapping between thrift structure and the enum.

As any python enum class expose the enum as a key, we can use this to have an implicit mapping between gp param and kats enum.

This diff enable user to use the seasonality name and the code will convert it to enum during initialization

Differential Revision: D51238962

fbshipit-source-id: 5f35f8d8ffcfe3db6b498d1bcdb460004e76c579
  • Loading branch information
Wael Ben Zid El Guebsi authored and facebook-github-bot committed Nov 15, 2023
1 parent 9281502 commit 200b5b4
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 1 deletion.
22 changes: 21 additions & 1 deletion kats/detectors/prophet_detector.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,18 +138,37 @@ class SeasonalityTypes(Enum):
EMPTY_LIST: List[SeasonalityTypes] = []


def to_seasonality(seasonality: Union[str, SeasonalityTypes]) -> SeasonalityTypes:
if isinstance(seasonality, str):
try:
return SeasonalityTypes[seasonality.upper()]
except KeyError:
raise ValueError(
f"Invalid seasonality type: {seasonality}. Valid types are: {list(SeasonalityTypes)}"
)
elif isinstance(seasonality, SeasonalityTypes):
return seasonality
else:
raise ValueError(
f"Expected string or SeasonalityTypes, got {type(seasonality)} instead"
)


def seasonalities_to_dict(
seasonalities: Union[
SeasonalityTypes,
List[SeasonalityTypes],
List[str],
Dict[SeasonalityTypes, Union[bool, str]],
]
) -> Dict[SeasonalityTypes, Union[bool, str]]:

if isinstance(seasonalities, SeasonalityTypes):
seasonalities = {seasonalities: True}
elif isinstance(seasonalities, list):
seasonalities = {seasonality: True for seasonality in seasonalities}
seasonalities = {
to_seasonality(seasonality): True for seasonality in seasonalities
}
elif seasonalities is None:
seasonalities = {}
return seasonalities
Expand Down Expand Up @@ -253,6 +272,7 @@ def __init__(
Union[
SeasonalityTypes,
List[SeasonalityTypes],
List[str],
Dict[SeasonalityTypes, Union[bool, str]],
]
] = EMPTY_LIST,
Expand Down
20 changes: 20 additions & 0 deletions kats/tests/detectors/test_prophet_detector.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import random
from datetime import timedelta
from typing import Union
from unittest import TestCase

import numpy as np
Expand All @@ -17,6 +18,7 @@
ProphetScoreFunction,
ProphetTrendDetectorModel,
SeasonalityTypes,
to_seasonality,
)
from kats.utils.simulator import Simulator
from parameterized.parameterized import parameterized
Expand Down Expand Up @@ -872,3 +874,21 @@ def test_pmm_use_case(self) -> None:
self.assertEqual(
response_wo_historical_data.scores.value.shape, hist_ts.value.shape
)

# pyre-fixme[56]: Pyre was not able to infer the type of the decorator `parameter...
@parameterized.expand(
[
("day", SeasonalityTypes.DAY),
("week", SeasonalityTypes.WEEK),
("weekend", SeasonalityTypes.WEEKEND),
("year", SeasonalityTypes.YEAR),
(SeasonalityTypes.DAY, SeasonalityTypes.DAY),
(SeasonalityTypes.WEEK, SeasonalityTypes.WEEK),
(SeasonalityTypes.WEEKEND, SeasonalityTypes.WEEKEND),
(SeasonalityTypes.YEAR, SeasonalityTypes.YEAR),
]
)
def test_to_seasonality(
self, actual: Union[str, SeasonalityTypes], expected: SeasonalityTypes
) -> None:
self.assertEqual(to_seasonality(actual), expected)

0 comments on commit 200b5b4

Please sign in to comment.