1pip install autogluon.timeseries
2
3from autogluon.timeseries import TimeSeriesDataFrame, TimeSeriesPredictor
4
5# Your data: DataFrame with columns [item_id, timestamp, target]
6train_data = TimeSeriesDataFrame.from_data_frame(your_df, id_column="item_id", timestamp_column="date")
7
8predictor = TimeSeriesPredictor(
9 prediction_length=12, # your forecast horizon
10 freq="ME",
11 eval_metric="SMAPE",
12).fit(
13 train_data,
14 hyperparameters={
15 # Fine-tuned Chronos-2 (adapts to YOUR seasonal pattern)
16 "Chronos2": [
17 {"fine_tune": True, "fine_tune_steps": 2000, "fine_tune_lr": 1e-5,
18 "ag_args": {"name_suffix": "FineTuned"}},
19 {"ag_args": {"name_suffix": "ZeroShot"}}, # zero-shot baseline
20 ],
21 # Statistical models (AutoARIMA already works well for you)
22 "AutoARIMA": {},
23 "AutoETS": {},
24 "AutoTheta": {},
25 },
26 enable_ensemble=True, # learns optimal blend of all models
27 time_limit=3600,
28)
29
30# The ensemble will learn to weight AutoARIMA heavily for seasonal parts
31# and Chronos-2 for trend/anomaly detection
32predictions = predictor.predict(train_data)
33predictor.leaderboard()
1pip install statsforecast
2
3from statsforecast import StatsForecast
4from statsforecast.models import AutoARIMA, AutoETS, AutoTheta, AutoCES, OptimizedTheta
5
6sf = StatsForecast(
7 models=[
8 AutoARIMA(season_length=12),
9 AutoETS(season_length=12),
10 AutoTheta(season_length=12),
11 OptimizedTheta(season_length=12),
12 AutoCES(season_length=12),
13 ],
14 freq="ME",
15 n_jobs=1,
16)
17sf.fit(your_df) # DataFrame: unique_id, ds, y
18predictions = sf.predict(h=12, level=[80, 95])
19
20# Simple average of top models often beats any individual model
21ensemble = predictions[["AutoARIMA", "AutoETS", "AutoTheta"]].mean(axis=1)
1pip install "tirex-ts[all]" statsforecast
2
3import torch, numpy as np
4from tirex import load_model
5from statsforecast import StatsForecast
6from statsforecast.models import AutoARIMA
7
8# TiRex forecast
9model = load_model("NX-AI/TiRex")
10data = torch.tensor(your_history, dtype=torch.float32).unsqueeze(0)
11_, tirex_forecast = model.forecast(context=data, prediction_length=12)
12
13# AutoARIMA forecast
14sf = StatsForecast(models=[AutoARIMA(season_length=12)], freq="ME")
15sf.fit(df)
16arima_forecast = sf.predict(h=12)["AutoARIMA"].values
17
18# Optimal blend (tune alpha on your validation data)
19alpha = 0.3 # 30% ARIMA + 70% TiRex (typical for regular seasonal data)
20hybrid = alpha * arima_forecast + (1-alpha) * tirex_forecast.numpy().flatten()
1from scipy.optimize import minimize
2
3def optimize_blend(forecasts_dict, actuals):
4 """Find optimal weights minimizing sMAPE."""
5 names = list(forecasts_dict.keys())
6
7 def objective(weights):
8 w = np.abs(weights) / np.abs(weights).sum()
9 blend = sum(w[i] * forecasts_dict[names[i]] for i in range(len(names)))
10 return 200 * np.mean(np.abs(blend - actuals) / (np.abs(blend) + np.abs(actuals) + 1e-8))
11
12 result = minimize(objective, x0=np.ones(len(names))/len(names), method="Nelder-Mead")
13 weights = np.abs(result.x) / np.abs(result.x).sum()
14 return dict(zip(names, weights))
15
16# Use on your CV folds
17optimal_weights = optimize_blend(
18 {"AutoARIMA": arima_cv, "TiRex": tirex_cv, "Chronos2": c2_cv},
19 actual_cv
20)
1{
2 "TiRex": 0.751,
3 "Chronos-2": 0.114,
4 "AutoARIMA": 0.052,
5 "AutoTheta": 0.041,
6 "OptimizedTheta": 0.011,
7 "STL+TiRex": 0.025
8}