| name | time-series-analysis |
| description | Analyse and model time series data for forecasting, anomaly detection, and trend analysis. Outputs decomposition approach, forecasting model selection, evaluation metrics, and production pipeline. |
| argument-hint | ["metric type","seasonality patterns","forecast horizon","accuracy requirements"] |
| allowed-tools | Read, Write, Bash |
Time Series Analysis
Time series data has temporal structure — order matters, recent values correlate with past values, and patterns repeat seasonally. Standard ML models that ignore this structure perform poorly. Time series analysis extracts trend, seasonality, and noise to enable accurate forecasting and anomaly detection.
Decomposition
from statsmodels.tsa.seasonal import seasonal_decompose
import pandas as pd
import numpy as np
df = pd.read_csv("sales.csv", parse_dates=["date"], index_col="date")
ts = df["revenue"].asfreq("D")
result = seasonal_decompose(ts, model="multiplicative", period=7)
print(f"Trend range: {result.trend.min():.0f} - {result.trend.max():.0f}")
print(f"Seasonal range: {result.seasonal.min():.3f} - {result.seasonal.max():.3f}")
print(f"Residual std: {result.resid.std():.3f}")
result.plot()
Forecasting with Prophet
from prophet import Prophet
from prophet.diagnostics import cross_validation, performance_metrics
import pandas as pd
df_prophet = df.reset_index().rename(columns={"date": "ds", "revenue": "y"})
model = Prophet(
seasonality_mode="multiplicative",
yearly_seasonality=True,
weekly_seasonality=True,
daily_seasonality=False,
changepoint_prior_scale=0.05,
seasonality_prior_scale=10.0,
)
model.add_seasonality(name="monthly", period=30.5, fourier_order=5)
from prophet.make_holidays import make_holidays_df
holidays = make_holidays_df(year_list=[2023, 2024], country="US")
model = Prophet(holidays=holidays, holidays_prior_scale=10.0)
model.fit(df_prophet)
future = model.make_future_dataframe(periods=90)
forecast = model.predict(future)
print(forecast[["ds", "yhat", "yhat_lower", "yhat_upper"]].tail(10))
cv_results = cross_validation(
model,
initial="365 days",
period=,
horizon=,
)
metrics = performance_metrics(cv_results)
()
()
Anomaly Detection
from statsmodels.tsa.statespace.sarimax import SARIMAX
def detect_anomalies(ts: pd.Series, sigma_threshold: float = 3.0) -> pd.Series:
"""Flag points more than N standard deviations from expected."""
model = SARIMAX(ts, order=(1,1,1), seasonal_order=(1,1,1,7))
result = model.fit(disp=False)
residuals = result.resid
mean_resid = residuals.mean()
std_resid = residuals.std()
anomalies = abs(residuals - mean_resid) > sigma_threshold * std_resid
return anomalies
anomalies = detect_anomalies(ts)
print(f"Anomalous dates: {ts[anomalies].index.tolist()}")
Evaluation Metrics
def evaluate_forecast(actual: pd.Series, predicted: pd.Series) -> dict:
errors = actual - predicted
return {
"MAE": abs(errors).mean(),
"RMSE": (errors**2).mean()**0.5,
"MAPE": (abs(errors / actual)).mean() * 100,
"SMAPE": (2 * abs(errors) / (abs(actual) + abs(predicted))).mean() * 100,
"bias": errors.mean(),
}
Anti-Patterns to Avoid
| Anti-Pattern | Problem | Fix |
|---|
| Ignoring seasonality | Trend model misses weekly/yearly patterns | Decompose first; model seasonality explicitly |
| Training on test period | Data leakage inflates accuracy metrics | Strict temporal train/test split |
| Single point forecast only | No uncertainty quantification | Always produce prediction intervals |
| MAPE on near-zero values | Division by zero / unstable metric | Use SMAPE or MAE for low-volume series |
| One model for all series | High-volume and low-volume metrics need different models | Cluster series; model per cluster |
10 Rules
- Decompose before modelling — understand trend, seasonality, and noise separately.
- Never use random train/test splits — always split by time (train on past; test on future).
- Seasonal period must match domain knowledge — weekly for daily data, yearly for monthly.
- Multiplicative seasonality for revenue — additive for metrics that can be negative.
- Cross-validation uses walk-forward splits — not random k-fold.
- Produce intervals, not just point forecasts — uncertainty is as important as the estimate.
- MAPE is misleading for near-zero series — use SMAPE or MAE instead.
- Residuals should be white noise — autocorrelated residuals mean the model missed structure.
- Business events (promotions, holidays) are explicit features — don't let the model guess.
- Forecast accuracy degrades with horizon — report accuracy at multiple forecast horizons.