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
14 changes: 14 additions & 0 deletions tests/models/utils/test_forecaster.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import pytest
from utilsforecast.data import generate_series

from timecopilot.models.prophet import Prophet
from timecopilot.models.stats import SeasonalNaive
from timecopilot.models.utils.forecaster import (
QuantileConverter,
Expand Down Expand Up @@ -332,3 +333,16 @@ def test_detect_anomalies_short_series_error():
)
with pytest.raises(ValueError, match="Cannot perform anomaly detection"):
model.detect_anomalies(df, h=5, freq="D")


def test_prophet_detect_anomalies_short_series_error():
model = Prophet()
df = pd.DataFrame(
{
"unique_id": ["A", "A"],
"ds": pd.date_range("2023-01-01", periods=2, freq="D"),
"y": [1.0, 2.0],
}
)
with pytest.raises(ValueError, match="Cannot perform anomaly detection"):
model.detect_anomalies(df, h=1, freq="D")
9 changes: 8 additions & 1 deletion timecopilot/models/utils/forecaster.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from gluonts.time_feature.seasonality import (
get_seasonality as _get_seasonality,
)
from prophet import Prophet as ProphetBase
from scipy import stats
from tqdm import tqdm
from utilsforecast.plotting import plot_series
Expand Down Expand Up @@ -304,6 +305,7 @@ def detect_anomalies(
Args:
df (pd.DataFrame):
DataFrame containing the time series to detect anomalies.
Minimum series length is 1 higher for Prophet than other models.
Copy link

Copilot AI Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation comment is unclear and potentially misleading. It states "Minimum series length is 1 higher for Prophet than other models" but doesn't specify what that minimum is. Consider being more explicit, e.g., "For Prophet models, the minimum series length is h + 2 instead of h + 1."

Suggested change
Minimum series length is 1 higher for Prophet than other models.
For Prophet models, the minimum series length is `h + 2`; for other models, it is `h + 1`.

Copilot uses AI. Check for mistakes.
h (int, optional):
Forecast horizon specifying how many future steps to predict.
In each cross validation window. If not provided, the seasonality
Expand Down Expand Up @@ -348,14 +350,19 @@ def detect_anomalies(
min_series_length = df.groupby("unique_id").size().min()
# we require at least one observation before the first forecast
max_possible_windows = (min_series_length - 1) // h
# 3 row minimum for a df with Prophet
Copy link

Copilot AI Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment "3 row minimum for a df with Prophet" is imprecise. The actual minimum depends on the forecast horizon h. For h=1, the minimum is 3 rows, but for h=2, it would be 5 rows (2h+1). Consider updating the comment to clarify this relationship, e.g., "Prophet requires min_series_length >= 2h + 1".

Suggested change
# 3 row minimum for a df with Prophet
# Prophet requires min_series_length >= 2h + 1, where h is the forecast horizon

Copilot uses AI. Check for mistakes.
if isinstance(self, ProphetBase):
max_possible_windows -= 1
if n_windows is None:
_n_windows = max_possible_windows
else:
_n_windows = min(n_windows, max_possible_windows)
if _n_windows < 1:
# min series length should be 1 higher for Prophet than other models
exp_min_series_length = h + 2 if isinstance(self, ProphetBase) else h + 1
raise ValueError(
f"Cannot perform anomaly detection: series too short. "
f"Minimum series length required: {h + 1}, "
f"Minimum series length required: {exp_min_series_length}, "
f"actual minimum length: {min_series_length}"
)
cv_results = self.cross_validation(
Expand Down