|

How to Build a Forecasting Pipeline with TimeCopilot Using Foundation Models and Automated Anomaly Detection

✅

In this tutorial, we construct an end-to-end forecasting workflow with TimeCopilot. We put together a panel dataset containing actual airline passenger knowledge and a artificial seasonal collection with injected anomalies, then consider a numerous assortment of statistical, basis, and non-obligatory GPU-based forecasting fashions. We use rolling cross-validation and a number of error metrics to establish the strongest mannequin, generate probabilistic forecasts with prediction intervals, visualize future traits, and detect uncommon observations. Finally, we discover TimeCopilot’s non-obligatory LLM agent, which selects a forecasting mannequin and interprets its predictions into an accessible analytical response.

Installing TimeCopilot and Pinning Compatible NumPy and SciPy Versions

!pip set up -q "timecopilot" "utilsforecast" "matplotlib"
!pip set up -q --force-reinstall --no-deps "numpy==1.26.4" "scipy==1.13.1"
print("Setup full. Restarting the runtime to load clear binaries...")
import IPython
IPython.Application.occasion().kernel.do_shutdown(True)

We set up TimeCopilot, UtilsForecast, and Matplotlib to put together the forecasting atmosphere. We implement appropriate NumPy and SciPy variations to forestall binary conflicts. We then restart the Colab runtime so the up to date libraries load accurately.

Loading AirPassengers Data and Building a Synthetic Anomaly Panel

import os, warnings
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
warnings.filterwarnings("ignore")
pd.set_option("show.width", 160)
pd.set_option("show.max_columns", 30)
print("numpy:", np.__version__)
import scipy; print("scipy:", scipy.__version__)
strive:
   import torch
   HAS_GPU = torch.cuda.is_available()
besides Exception:
   HAS_GPU = False
print(f"GPU obtainable: {HAS_GPU}")
df = pd.read_csv(
   "https://timecopilot.s3.amazonaws.com/public/knowledge/air_passengers.csv",
   parse_dates=["ds"],
)
df["unique_id"] = df["unique_id"].astype(str)
rng = np.random.default_rng(7)
dates = df["ds"].distinctive(); n = len(dates)
synth = pd.DataBody({
   "unique_id": "Synthetic",
   "ds": dates,
   "y": (np.linspace(50, 250, n)
         + 40 * np.sin(2 * np.pi * np.arange(n) / 12)
         + rng.regular(0, 8, n)).spherical(2),
})
anomaly_idx = [30, 75, 120]
synth.loc[anomaly_idx, "y"] *= 2.2
panel = pd.concat([df[["unique_id", "ds", "y"]], synth], ignore_index=True)
print("nPanel form:", panel.form)
print(panel.groupby("unique_id")["y"].agg(["count", "mean", "min", "max"]))
H, FREQ = 12, "MS"

We import the required libraries, confirm the atmosphere, and detect GPU availability. We load the AirPassengers dataset and create a second artificial seasonal collection with injected spikes. We mix the 2 collection into a panel dataset and set the forecasting horizon and month-to-month frequency.

Configuring Statistical, Prophet, and Chronos Forecasting Models

from timecopilot.forecaster import TimeCopilotForecaster
from timecopilot.fashions.stats import AutoARIMA, AutoETS, SeasonalNaive, Theta
from timecopilot.fashions.prophet import Prophet
from timecopilot.fashions.basis.chronos import Chronos
chronos_repo = "amazon/chronos-bolt-small" if HAS_GPU else "amazon/chronos-bolt-tiny"
fashions = [
   SeasonalNaive(), AutoETS(), AutoARIMA(), Theta(), Prophet(),
   Chronos(repo_id=chronos_repo, alias="Chronos"),
]
if HAS_GPU:
   strive:
       from timecopilot.fashions.basis.timesfm import TimesFM
       fashions.append(TimesFM(repo_id="google/timesfm-2.0-500m-pytorch", alias="TimesFM"))
   besides Exception as e:
       print("Skipping TimesFM:", e)
tcf = TimeCopilotForecaster(fashions=fashions)
print("nModels:", [getattr(m, "alias", type(m).__name__) for m in models])

We configure a numerous assortment of statistical, Prophet, and Chronos forecasting fashions. We choose the Chronos mannequin measurement in accordance to the obtainable {hardware} and optionally embody TimesFM when a GPU is current. We then initialize TimeCopilotForecaster to handle all fashions by means of one constant interface.

Running Rolling Cross-Validation and Ranking Models by RMSE

print("nRunning cross-validation (sluggish step: basis weights obtain)...")
cv_df = tcf.cross_validation(df=panel, h=H, freq=FREQ, n_windows=3)
print(cv_df.head())
from utilsforecast.analysis import consider
from utilsforecast.losses import mae, rmse, mape
eval_df = consider(cv_df.drop(columns=["cutoff"]), metrics=[mae, rmse, mape])
print("n=== Per-series error (decrease = higher) ===")
print(eval_df.spherical(3))
model_cols = [c for c in eval_df.columns if c not in ("unique_id", "metric")]
leaderboard = (eval_df.groupby("metric")[model_cols].imply().T.sort_values("rmse"))
print("n=== Leaderboard (imply throughout collection) ===")
print(leaderboard.spherical(3))
best_model = leaderboard.index[0]
print(f"n>>> Best mannequin by imply RMSE: {best_model}")

We carry out rolling cross-validation throughout three home windows to measure every mannequin’s forecasting efficiency. We calculate MAE, RMSE, and MAPE for each collection and mixture the outcomes into a leaderboard. We establish the mannequin with the bottom imply RMSE for subsequent forecasting and visualization.

Generating Probabilistic Forecasts with Prediction Intervals

fcst_df = tcf.forecast(df=panel, h=H, freq=FREQ, degree=[80, 95])
print("nForecast columns:", checklist(fcst_df.columns))
def plot_series(uid, point_model=best_model):
   hist = panel[panel["unique_id"] == uid]; fc = fcst_df[fcst_df["unique_id"] == uid]
   plt.determine(figsize=(11, 4)); plt.plot(hist["ds"], hist["y"], coloration="black", label="historical past")
   if point_model in fc.columns:
       plt.plot(fc["ds"], fc[point_model], coloration="C0", label=f"{point_model} forecast")
       lo, hello = f"{point_model}-lo-95", f"{point_model}-hi-95"
       if lo in fc.columns and hello in fc.columns:
           plt.fill_between(fc["ds"], fc[lo], fc[hi], alpha=0.25, coloration="C0", label="95% interval")
   plt.title(f"{uid} — {point_model}"); plt.legend(); plt.tight_layout(); plt.present()
for uid in panel["unique_id"].distinctive():
   plot_series(uid)

We generate 12-month probabilistic forecasts with 80% and 95% prediction intervals. We outline a reusable plotting perform that shows historic values, level forecasts, and uncertainty ranges. We apply this perform to every collection to examine its noticed historical past with the anticipated future trajectory.

Detecting Anomalies Across the Forecasting Panel

print("nRunning anomaly detection...")
anomalies_df = tcf.detect_anomalies(df=panel, h=H, freq=FREQ, degree=99)
anom_cols = [c for c in anomalies_df.columns if c.endswith("-anomaly")]
if anom_cols:
   flagged = anomalies_df[anomalies_df[anom_cols].any(axis=1)]
   print(f"Flagged factors (>=1 mannequin): {len(flagged)}")
   print(flagged[["unique_id", "ds", "y"] + anom_cols].head(20).to_string(index=False))
   col = f"{best_model}-anomaly"
   if col not in anomalies_df.columns: col = anom_cols[0]
   sub = anomalies_df[anomalies_df["unique_id"] == "Synthetic"]
   pts = sub[sub[col] == True]
   plt.determine(figsize=(11, 4)); plt.plot(sub["ds"], sub["y"], coloration="black", label="worth")
   plt.scatter(pts["ds"], pts["y"], coloration="purple", zorder=5, label=f"anomaly ({col})")
   plt.title("Anomaly detection — Synthetic collection"); plt.legend(); plt.tight_layout(); plt.present()
else:
   print(anomalies_df.head())

Interpreting Forecasts with the TimeCopilot LLM Agent

from timecopilot import TimeCopilot
if os.environ.get("OPENAI_API_KEY") or os.environ.get("ANTHROPIC_API_KEY"):
   llm = "openai:gpt-4o" if os.environ.get("OPENAI_API_KEY") else "anthropic:claude-sonnet-4-5"
   tc = TimeCopilot(llm=llm, retries=3)
   single = panel[panel["unique_id"] == "AirPassengers"]
   end result = tc.forecast(df=single, freq=FREQ, h=H,
                        question="Total air passengers anticipated over the subsequent 12 months, and which months peak?")
   out = end result.output
   print("n=== AGENT REPORT ===")
   print("Selected mannequin:", out.selected_model)
   print("Beats SeasonalNaive:", out.is_better_than_seasonal_naive)
   print("Why:", out.reason_for_selection)
   print("Answer:", out.user_query_response)
   print(end result.fcst_df.head())
else:
   print("n[Agent section skipped] No LLM key. Everything above ran key-free.")
print("nDone. ✅")

We detect anomalies throughout the panel and visualize the flagged observations within the artificial collection. We optionally initialize the TimeCopilot LLM agent when an OpenAI or Anthropic API key’s obtainable. We use the agent to choose a mannequin, consider it towards SeasonalNaive, and clarify the forecast in response to a sensible query.

Conclusion

In conclusion, we created a unified TimeCopilot pipeline that takes us from knowledge preparation to mannequin analysis, probabilistic forecasting, visualization, anomaly detection, and agent-driven interpretation. We in contrast conventional statistical strategies with trendy basis fashions inside a constant cross-validation framework and chosen the best-performing strategy primarily based on goal error metrics. We additionally quantified forecast uncertainty by means of prediction intervals and recognized irregular observations throughout a number of time collection. By combining automated forecasting with an non-obligatory LLM agent, we produced each correct numerical predictions and clear, decision-oriented insights inside a single workflow.


Check out the Full Codes with Notebook. Also, be happy to comply with us on Twitter and don’t neglect to be a part of our 150k+ML SubReddit and Subscribe to our Newsletter. Wait! are you on telegram? now you can join us on telegram as well.

Need to accomplice with us for selling your GitHub Repo OR Hugging Face Page OR Product Release OR Webinar and so on.? Connect with us

The put up How to Build a Forecasting Pipeline with TimeCopilot Using Foundation Models and Automated Anomaly Detection appeared first on MarkTechPost.

Similar Posts