statsforecast / app.py
fmegahed's picture
Changed gr.Box to gr.Group
41099ef verified
raw
history blame contribute delete
35.2 kB
import pandas as pd
import matplotlib.pyplot as plt
import gradio as gr
import tempfile
import os
from datetime import datetime
from statsforecast import StatsForecast
from statsforecast.models import (
HistoricAverage,
Naive,
SeasonalNaive,
WindowAverage,
SeasonalWindowAverage,
AutoETS,
AutoARIMA
)
from utilsforecast.evaluation import evaluate
from utilsforecast.losses import *
# Function to load and process uploaded CSV
def load_data(file):
if file is None:
return None, "Please upload a CSV file"
try:
df = pd.read_csv(file)
required_cols = ['unique_id', 'ds', 'y']
missing_cols = [col for col in required_cols if col not in df.columns]
if missing_cols:
return None, f"Missing required columns: {', '.join(missing_cols)}"
df['ds'] = pd.to_datetime(df['ds'])
df = df.sort_values(['unique_id', 'ds']).reset_index(drop=True)
# Check for NaN values
if df['y'].isna().any():
return None, "Data contains missing values in the 'y' column"
return df, "Data loaded successfully!"
except Exception as e:
return None, f"Error loading data: {str(e)}"
# Function to generate and return a plot
def create_forecast_plot(forecast_df, original_df, title="Forecasting Results"):
plt.figure(figsize=(12, 7))
unique_ids = forecast_df['unique_id'].unique()
forecast_cols = [col for col in forecast_df.columns if col not in ['unique_id', 'ds', 'cutoff']]
colors = plt.cm.tab10.colors
for i, unique_id in enumerate(unique_ids):
original_data = original_df[original_df['unique_id'] == unique_id]
plt.plot(original_data['ds'], original_data['y'], 'k-', linewidth=2, label=f'{unique_id} (Actual)')
forecast_data = forecast_df[forecast_df['unique_id'] == unique_id]
for j, col in enumerate(forecast_cols):
if col in forecast_data.columns:
plt.plot(forecast_data['ds'], forecast_data[col],
color=colors[j % len(colors)],
linestyle='--',
linewidth=1.5,
label=f'{col}')
plt.title(title, fontsize=16)
plt.xlabel('Date', fontsize=12)
plt.ylabel('Value', fontsize=12)
plt.grid(True, alpha=0.3)
plt.legend(loc='best')
plt.tight_layout()
# Format date labels better
fig = plt.gcf()
ax = plt.gca()
fig.autofmt_xdate()
return fig
# Function to create a plot for future forecasts
def create_future_forecast_plot(forecast_df, original_df):
plt.figure(figsize=(12, 7))
unique_ids = forecast_df['unique_id'].unique()
forecast_cols = [col for col in forecast_df.columns if col not in ['unique_id', 'ds']]
colors = plt.cm.tab10.colors
for i, unique_id in enumerate(unique_ids):
# Plot historical data
original_data = original_df[original_df['unique_id'] == unique_id]
plt.plot(original_data['ds'], original_data['y'], 'k-', linewidth=2, label=f'{unique_id} (Historical)')
# Plot forecast data with shaded vertical line separator
forecast_data = forecast_df[forecast_df['unique_id'] == unique_id]
# Add vertical line at the forecast start
if not forecast_data.empty and not original_data.empty:
forecast_start = forecast_data['ds'].min()
plt.axvline(x=forecast_start, color='gray', linestyle='--', alpha=0.5)
for j, col in enumerate(forecast_cols):
if col in forecast_data.columns:
plt.plot(forecast_data['ds'], forecast_data[col],
color=colors[j % len(colors)],
linestyle='--',
linewidth=1.5,
label=f'{col}')
plt.title('Future Forecast', fontsize=16)
plt.xlabel('Date', fontsize=12)
plt.ylabel('Value', fontsize=12)
plt.grid(True, alpha=0.3)
plt.legend(loc='best')
plt.tight_layout()
# Format date labels better
fig = plt.gcf()
ax = plt.gca()
fig.autofmt_xdate()
return fig
# Function to export results to CSV
def export_results(eval_df, cv_results, future_forecasts):
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
# Create temp directory if it doesn't exist
temp_dir = tempfile.mkdtemp()
result_files = []
if eval_df is not None:
eval_path = os.path.join(temp_dir, f"evaluation_metrics_{timestamp}.csv")
eval_df.to_csv(eval_path, index=False)
result_files.append(eval_path)
if cv_results is not None:
cv_path = os.path.join(temp_dir, f"cross_validation_results_{timestamp}.csv")
cv_results.to_csv(cv_path, index=False)
result_files.append(cv_path)
if future_forecasts is not None:
forecast_path = os.path.join(temp_dir, f"forecasts_{timestamp}.csv")
future_forecasts.to_csv(forecast_path, index=False)
result_files.append(forecast_path)
return result_files
# Main forecasting logic
def run_forecast(
file,
frequency,
eval_strategy,
horizon,
step_size,
num_windows,
use_historical_avg,
use_naive,
use_seasonal_naive,
seasonality,
use_window_avg,
window_size,
use_seasonal_window_avg,
seasonal_window_size,
use_autoets,
use_autoarima,
future_horizon
):
df, message = load_data(file)
if df is None:
return None, None, None, None, None, None, message
models = []
model_aliases = []
if use_historical_avg:
models.append(HistoricAverage(alias='historical_average'))
model_aliases.append('historical_average')
if use_naive:
models.append(Naive(alias='naive'))
model_aliases.append('naive')
if use_seasonal_naive:
models.append(SeasonalNaive(season_length=seasonality, alias='seasonal_naive'))
model_aliases.append('seasonal_naive')
if use_window_avg:
models.append(WindowAverage(window_size=window_size, alias='window_average'))
model_aliases.append('window_average')
if use_seasonal_window_avg:
models.append(SeasonalWindowAverage(season_length=seasonality, window_size=seasonal_window_size, alias='seasonal_window_average'))
model_aliases.append('seasonal_window_average')
if use_autoets:
models.append(AutoETS(alias='autoets', season_length=seasonality))
model_aliases.append('autoets')
if use_autoarima:
models.append(AutoARIMA(alias='autoarima', season_length=seasonality))
model_aliases.append('autoarima')
if not models:
return None, None, None, None, None, None, "Please select at least one forecasting model"
sf = StatsForecast(models=models, freq=frequency, n_jobs=-1)
try:
# Run cross-validation
if eval_strategy == "Cross Validation":
cv_results = sf.cross_validation(df=df, h=horizon, step_size=step_size, n_windows=num_windows)
evaluation = evaluate(df=cv_results, metrics=[bias, mae, rmse, mape], models=model_aliases)
eval_df = pd.DataFrame(evaluation).reset_index()
fig_validation = create_forecast_plot(cv_results, df, "Cross Validation Results")
else: # Fixed window
cv_results = sf.cross_validation(df=df, h=horizon, step_size=10, n_windows=1) # any step size for 1 window
evaluation = evaluate(df=cv_results, metrics=[bias, mae, rmse, mape], models=model_aliases)
eval_df = pd.DataFrame(evaluation).reset_index()
fig_validation = create_forecast_plot(cv_results, df, "Fixed Window Validation Results")
# Generate future forecasts
future_forecasts = sf.forecast(df=df, h=future_horizon)
fig_future = create_future_forecast_plot(future_forecasts, df)
# Export results
export_files = export_results(eval_df, cv_results, future_forecasts)
return eval_df, cv_results, fig_validation, future_forecasts, fig_future, export_files, "Analysis completed successfully!"
except Exception as e:
return None, None, None, None, None, None, f"Error during forecasting: {str(e)}"
# Sample CSV file generation
def download_sample():
sample_data = """unique_id,ds,y
^GSPC,2023-01-03,3824.139892578125
^GSPC,2023-01-04,3852.969970703125
^GSPC,2023-01-05,3808.10009765625
^GSPC,2023-01-06,3895.080078125
^GSPC,2023-01-09,3892.090087890625
^GSPC,2023-01-10,3919.25
^GSPC,2023-01-11,3969.610107421875
^GSPC,2023-01-12,3983.169921875
^GSPC,2023-01-13,3999.090087890625
^GSPC,2023-01-17,3990.969970703125
^GSPC,2023-01-18,3928.860107421875
^GSPC,2023-01-19,3898.85009765625
^GSPC,2023-01-20,3972.610107421875
^GSPC,2023-01-23,4019.81005859375
^GSPC,2023-01-24,4016.949951171875
^GSPC,2023-01-25,4016.219970703125
^GSPC,2023-01-26,4060.429931640625
^GSPC,2023-01-27,4070.56005859375
^GSPC,2023-01-30,4017.77001953125
^GSPC,2023-01-31,4076.60009765625
^GSPC,2023-02-01,4119.2099609375
^GSPC,2023-02-02,4179.759765625
^GSPC,2023-02-03,4136.47998046875
^GSPC,2023-02-06,4111.080078125
^GSPC,2023-02-07,4164
^GSPC,2023-02-08,4117.85986328125
^GSPC,2023-02-09,4081.5
^GSPC,2023-02-10,4090.4599609375
^GSPC,2023-02-13,4137.2900390625
^GSPC,2023-02-14,4136.1298828125
^GSPC,2023-02-15,4147.60009765625
^GSPC,2023-02-16,4090.409912109375
^GSPC,2023-02-17,4079.090087890625
^GSPC,2023-02-21,3997.340087890625
^GSPC,2023-02-22,3991.050048828125
^GSPC,2023-02-23,4012.320068359375
^GSPC,2023-02-24,3970.0400390625
^GSPC,2023-02-27,3982.239990234375
^GSPC,2023-02-28,3970.14990234375
^GSPC,2023-03-01,3951.389892578125
^GSPC,2023-03-02,3981.35009765625
^GSPC,2023-03-03,4045.639892578125
^GSPC,2023-03-06,4048.419921875
^GSPC,2023-03-07,3986.3701171875
^GSPC,2023-03-08,3992.010009765625
^GSPC,2023-03-09,3918.320068359375
^GSPC,2023-03-10,3861.590087890625
^GSPC,2023-03-13,3855.760009765625
^GSPC,2023-03-14,3919.2900390625
^GSPC,2023-03-15,3891.929931640625
^GSPC,2023-03-16,3960.280029296875
^GSPC,2023-03-17,3916.639892578125
^GSPC,2023-03-20,3951.570068359375
^GSPC,2023-03-21,4002.8701171875
^GSPC,2023-03-22,3936.969970703125
^GSPC,2023-03-23,3948.719970703125
^GSPC,2023-03-24,3970.989990234375
^GSPC,2023-03-27,3977.530029296875
^GSPC,2023-03-28,3971.27001953125
^GSPC,2023-03-29,4027.81005859375
^GSPC,2023-03-30,4050.830078125
^GSPC,2023-03-31,4109.31005859375
^GSPC,2023-04-03,4124.509765625
^GSPC,2023-04-04,4100.60009765625
^GSPC,2023-04-05,4090.3798828125
^GSPC,2023-04-06,4105.02001953125
^GSPC,2023-04-10,4109.10986328125
^GSPC,2023-04-11,4108.93994140625
^GSPC,2023-04-12,4091.949951171875
^GSPC,2023-04-13,4146.22021484375
^GSPC,2023-04-14,4137.64013671875
^GSPC,2023-04-17,4151.31982421875
^GSPC,2023-04-18,4154.8701171875
^GSPC,2023-04-19,4154.52001953125
^GSPC,2023-04-20,4129.7900390625
^GSPC,2023-04-21,4133.52001953125
^GSPC,2023-04-24,4137.0400390625
^GSPC,2023-04-25,4071.6298828125
^GSPC,2023-04-26,4055.989990234375
^GSPC,2023-04-27,4135.35009765625
^GSPC,2023-04-28,4169.47998046875
^GSPC,2023-05-01,4167.8701171875
^GSPC,2023-05-02,4119.580078125
^GSPC,2023-05-03,4090.75
^GSPC,2023-05-04,4061.219970703125
^GSPC,2023-05-05,4136.25
^GSPC,2023-05-08,4138.1201171875
^GSPC,2023-05-09,4119.169921875
^GSPC,2023-05-10,4137.64013671875
^GSPC,2023-05-11,4130.6201171875
^GSPC,2023-05-12,4124.080078125
^GSPC,2023-05-15,4136.27978515625
^GSPC,2023-05-16,4109.89990234375
^GSPC,2023-05-17,4158.77001953125
^GSPC,2023-05-18,4198.0498046875
^GSPC,2023-05-19,4191.97998046875
^GSPC,2023-05-22,4192.6298828125
^GSPC,2023-05-23,4145.580078125
^GSPC,2023-05-24,4115.240234375
^GSPC,2023-05-25,4151.27978515625
^GSPC,2023-05-26,4205.4501953125
^GSPC,2023-05-30,4205.52001953125
^GSPC,2023-05-31,4179.830078125
^GSPC,2023-06-01,4221.02001953125
^GSPC,2023-06-02,4282.3701171875
^GSPC,2023-06-05,4273.7900390625
^GSPC,2023-06-06,4283.85009765625
^GSPC,2023-06-07,4267.52001953125
^GSPC,2023-06-08,4293.93017578125
^GSPC,2023-06-09,4298.85986328125
^GSPC,2023-06-12,4338.93017578125
^GSPC,2023-06-13,4369.009765625
^GSPC,2023-06-14,4372.58984375
^GSPC,2023-06-15,4425.83984375
^GSPC,2023-06-16,4409.58984375
^GSPC,2023-06-20,4388.7099609375
^GSPC,2023-06-21,4365.68994140625
^GSPC,2023-06-22,4381.89013671875
^GSPC,2023-06-23,4348.330078125
^GSPC,2023-06-26,4328.81982421875
^GSPC,2023-06-27,4378.41015625
^GSPC,2023-06-28,4376.85986328125
^GSPC,2023-06-29,4396.43994140625
^GSPC,2023-06-30,4450.3798828125
^GSPC,2023-07-03,4455.58984375
^GSPC,2023-07-05,4446.81982421875
^GSPC,2023-07-06,4411.58984375
^GSPC,2023-07-07,4398.9501953125
^GSPC,2023-07-10,4409.52978515625
^GSPC,2023-07-11,4439.259765625
^GSPC,2023-07-12,4472.16015625
^GSPC,2023-07-13,4510.0400390625
^GSPC,2023-07-14,4505.419921875
^GSPC,2023-07-17,4522.7900390625
^GSPC,2023-07-18,4554.97998046875
^GSPC,2023-07-19,4565.72021484375
^GSPC,2023-07-20,4534.8701171875
^GSPC,2023-07-21,4536.33984375
^GSPC,2023-07-24,4554.64013671875
^GSPC,2023-07-25,4567.4599609375
^GSPC,2023-07-26,4566.75
^GSPC,2023-07-27,4537.41015625
^GSPC,2023-07-28,4582.22998046875
^GSPC,2023-07-31,4588.9599609375
^GSPC,2023-08-01,4576.72998046875
^GSPC,2023-08-02,4513.39013671875
^GSPC,2023-08-03,4501.89013671875
^GSPC,2023-08-04,4478.02978515625
^GSPC,2023-08-07,4518.43994140625
^GSPC,2023-08-08,4499.3798828125
^GSPC,2023-08-09,4467.7099609375
^GSPC,2023-08-10,4468.830078125
^GSPC,2023-08-11,4464.0498046875
^GSPC,2023-08-14,4489.72021484375
^GSPC,2023-08-15,4437.85986328125
^GSPC,2023-08-16,4404.330078125
^GSPC,2023-08-17,4370.35986328125
^GSPC,2023-08-18,4369.7099609375
^GSPC,2023-08-21,4399.77001953125
^GSPC,2023-08-22,4387.5498046875
^GSPC,2023-08-23,4436.009765625
^GSPC,2023-08-24,4376.31005859375
^GSPC,2023-08-25,4405.7099609375
^GSPC,2023-08-28,4433.31005859375
^GSPC,2023-08-29,4497.6298828125
^GSPC,2023-08-30,4514.8701171875
^GSPC,2023-08-31,4507.66015625
^GSPC,2023-09-01,4515.77001953125
^GSPC,2023-09-05,4496.830078125
^GSPC,2023-09-06,4465.47998046875
^GSPC,2023-09-07,4451.14013671875
^GSPC,2023-09-08,4457.490234375
^GSPC,2023-09-11,4487.4599609375
^GSPC,2023-09-12,4461.89990234375
^GSPC,2023-09-13,4467.43994140625
^GSPC,2023-09-14,4505.10009765625
^GSPC,2023-09-15,4450.31982421875
^GSPC,2023-09-18,4453.52978515625
^GSPC,2023-09-19,4443.9501953125
^GSPC,2023-09-20,4402.2001953125
^GSPC,2023-09-21,4330
^GSPC,2023-09-22,4320.06005859375
^GSPC,2023-09-25,4337.43994140625
^GSPC,2023-09-26,4273.52978515625
^GSPC,2023-09-27,4274.509765625
^GSPC,2023-09-28,4299.7001953125
^GSPC,2023-09-29,4288.0498046875
^GSPC,2023-10-02,4288.39013671875
^GSPC,2023-10-03,4229.4501953125
^GSPC,2023-10-04,4263.75
^GSPC,2023-10-05,4258.18994140625
^GSPC,2023-10-06,4308.5
^GSPC,2023-10-09,4335.66015625
^GSPC,2023-10-10,4358.240234375
^GSPC,2023-10-11,4376.9501953125
^GSPC,2023-10-12,4349.60986328125
^GSPC,2023-10-13,4327.77978515625
^GSPC,2023-10-16,4373.6298828125
^GSPC,2023-10-17,4373.2001953125
^GSPC,2023-10-18,4314.60009765625
^GSPC,2023-10-19,4278
^GSPC,2023-10-20,4224.16015625
^GSPC,2023-10-23,4217.0400390625
^GSPC,2023-10-24,4247.68017578125
^GSPC,2023-10-25,4186.77001953125
^GSPC,2023-10-26,4137.22998046875
^GSPC,2023-10-27,4117.3701171875
^GSPC,2023-10-30,4166.81982421875
^GSPC,2023-10-31,4193.7998046875
^GSPC,2023-11-01,4237.85986328125
^GSPC,2023-11-02,4317.77978515625
^GSPC,2023-11-03,4358.33984375
^GSPC,2023-11-06,4365.97998046875
^GSPC,2023-11-07,4378.3798828125
^GSPC,2023-11-08,4382.77978515625
^GSPC,2023-11-09,4347.35009765625
^GSPC,2023-11-10,4415.240234375
^GSPC,2023-11-13,4411.5498046875
^GSPC,2023-11-14,4495.7001953125
^GSPC,2023-11-15,4502.8798828125
^GSPC,2023-11-16,4508.240234375
^GSPC,2023-11-17,4514.02001953125
^GSPC,2023-11-20,4547.3798828125
^GSPC,2023-11-21,4538.18994140625
^GSPC,2023-11-22,4556.6201171875
^GSPC,2023-11-24,4559.33984375
^GSPC,2023-11-27,4550.43017578125
^GSPC,2023-11-28,4554.89013671875
^GSPC,2023-11-29,4550.580078125
^GSPC,2023-11-30,4567.7998046875
^GSPC,2023-12-01,4594.6298828125
^GSPC,2023-12-04,4569.77978515625
^GSPC,2023-12-05,4567.18017578125
^GSPC,2023-12-06,4549.33984375
^GSPC,2023-12-07,4585.58984375
^GSPC,2023-12-08,4604.3701171875
^GSPC,2023-12-11,4622.43994140625
^GSPC,2023-12-12,4643.7001953125
^GSPC,2023-12-13,4707.08984375
^GSPC,2023-12-14,4719.5498046875
^GSPC,2023-12-15,4719.18994140625
^GSPC,2023-12-18,4740.56005859375
^GSPC,2023-12-19,4768.3701171875
^GSPC,2023-12-20,4698.35009765625
^GSPC,2023-12-21,4746.75
^GSPC,2023-12-22,4754.6298828125
^GSPC,2023-12-26,4774.75
^GSPC,2023-12-27,4781.580078125
^GSPC,2023-12-28,4783.35009765625
^GSPC,2023-12-29,4769.830078125
^GSPC,2024-01-02,4742.830078125
^GSPC,2024-01-03,4704.81005859375
^GSPC,2024-01-04,4688.68017578125
^GSPC,2024-01-05,4697.240234375
^GSPC,2024-01-08,4763.5400390625
^GSPC,2024-01-09,4756.5
^GSPC,2024-01-10,4783.4501953125
^GSPC,2024-01-11,4780.240234375
^GSPC,2024-01-12,4783.830078125
^GSPC,2024-01-16,4765.97998046875
^GSPC,2024-01-17,4739.2099609375
^GSPC,2024-01-18,4780.93994140625
^GSPC,2024-01-19,4839.81005859375
^GSPC,2024-01-22,4850.43017578125
^GSPC,2024-01-23,4864.60009765625
^GSPC,2024-01-24,4868.5498046875
^GSPC,2024-01-25,4894.16015625
^GSPC,2024-01-26,4890.97021484375
^GSPC,2024-01-29,4927.93017578125
^GSPC,2024-01-30,4924.97021484375
^GSPC,2024-01-31,4845.64990234375
^GSPC,2024-02-01,4906.18994140625
^GSPC,2024-02-02,4958.60986328125
^GSPC,2024-02-05,4942.81005859375
^GSPC,2024-02-06,4954.22998046875
^GSPC,2024-02-07,4995.06005859375
^GSPC,2024-02-08,4997.91015625
^GSPC,2024-02-09,5026.60986328125
^GSPC,2024-02-12,5021.83984375
^GSPC,2024-02-13,4953.169921875
^GSPC,2024-02-14,5000.6201171875
^GSPC,2024-02-15,5029.72998046875
^GSPC,2024-02-16,5005.56982421875
^GSPC,2024-02-20,4975.509765625
^GSPC,2024-02-21,4981.7998046875
^GSPC,2024-02-22,5087.02978515625
^GSPC,2024-02-23,5088.7998046875
^GSPC,2024-02-26,5069.52978515625
^GSPC,2024-02-27,5078.18017578125
^GSPC,2024-02-28,5069.759765625
^GSPC,2024-02-29,5096.27001953125
^GSPC,2024-03-01,5137.080078125
^GSPC,2024-03-04,5130.9501953125
^GSPC,2024-03-05,5078.64990234375
^GSPC,2024-03-06,5104.759765625
^GSPC,2024-03-07,5157.35986328125
^GSPC,2024-03-08,5123.68994140625
^GSPC,2024-03-11,5117.93994140625
^GSPC,2024-03-12,5175.27001953125
^GSPC,2024-03-13,5165.31005859375
^GSPC,2024-03-14,5150.47998046875
^GSPC,2024-03-15,5117.08984375
^GSPC,2024-03-18,5149.419921875
^GSPC,2024-03-19,5178.509765625
^GSPC,2024-03-20,5224.6201171875
^GSPC,2024-03-21,5241.52978515625
^GSPC,2024-03-22,5234.18017578125
^GSPC,2024-03-25,5218.18994140625
^GSPC,2024-03-26,5203.580078125
^GSPC,2024-03-27,5248.490234375
^GSPC,2024-03-28,5254.35009765625
^GSPC,2024-04-01,5243.77001953125
^GSPC,2024-04-02,5205.81005859375
^GSPC,2024-04-03,5211.490234375
^GSPC,2024-04-04,5147.2099609375
^GSPC,2024-04-05,5204.33984375
^GSPC,2024-04-08,5202.39013671875
^GSPC,2024-04-09,5209.91015625
^GSPC,2024-04-10,5160.64013671875
^GSPC,2024-04-11,5199.06005859375
^GSPC,2024-04-12,5123.41015625
^GSPC,2024-04-15,5061.81982421875
^GSPC,2024-04-16,5051.41015625
^GSPC,2024-04-17,5022.2099609375
^GSPC,2024-04-18,5011.1201171875
^GSPC,2024-04-19,4967.22998046875
^GSPC,2024-04-22,5010.60009765625
^GSPC,2024-04-23,5070.5498046875
^GSPC,2024-04-24,5071.6298828125
^GSPC,2024-04-25,5048.419921875
^GSPC,2024-04-26,5099.9599609375
^GSPC,2024-04-29,5116.169921875
^GSPC,2024-04-30,5035.68994140625
^GSPC,2024-05-01,5018.39013671875
^GSPC,2024-05-02,5064.2001953125
^GSPC,2024-05-03,5127.7900390625
^GSPC,2024-05-06,5180.740234375
^GSPC,2024-05-07,5187.7001953125
^GSPC,2024-05-08,5187.669921875
^GSPC,2024-05-09,5214.080078125
^GSPC,2024-05-10,5222.68017578125
^GSPC,2024-05-13,5221.419921875
^GSPC,2024-05-14,5246.68017578125
^GSPC,2024-05-15,5308.14990234375
^GSPC,2024-05-16,5297.10009765625
^GSPC,2024-05-17,5303.27001953125
^GSPC,2024-05-20,5308.1298828125
^GSPC,2024-05-21,5321.41015625
^GSPC,2024-05-22,5307.009765625
^GSPC,2024-05-23,5267.83984375
^GSPC,2024-05-24,5304.72021484375
^GSPC,2024-05-28,5306.0400390625
^GSPC,2024-05-29,5266.9501953125
^GSPC,2024-05-30,5235.47998046875
^GSPC,2024-05-31,5277.509765625
^GSPC,2024-06-03,5283.39990234375
^GSPC,2024-06-04,5291.33984375
^GSPC,2024-06-05,5354.02978515625
^GSPC,2024-06-06,5352.9599609375
^GSPC,2024-06-07,5346.990234375
^GSPC,2024-06-10,5360.7900390625
^GSPC,2024-06-11,5375.31982421875
^GSPC,2024-06-12,5421.02978515625
^GSPC,2024-06-13,5433.740234375
^GSPC,2024-06-14,5431.60009765625
^GSPC,2024-06-17,5473.22998046875
^GSPC,2024-06-18,5487.02978515625
^GSPC,2024-06-20,5473.169921875
^GSPC,2024-06-21,5464.6201171875
^GSPC,2024-06-24,5447.8701171875
^GSPC,2024-06-25,5469.2998046875
^GSPC,2024-06-26,5477.89990234375
^GSPC,2024-06-27,5482.8701171875
^GSPC,2024-06-28,5460.47998046875
^GSPC,2024-07-01,5475.08984375
^GSPC,2024-07-02,5509.009765625
^GSPC,2024-07-03,5537.02001953125
^GSPC,2024-07-05,5567.18994140625
^GSPC,2024-07-08,5572.85009765625
^GSPC,2024-07-09,5576.97998046875
^GSPC,2024-07-10,5633.91015625
^GSPC,2024-07-11,5584.5400390625
^GSPC,2024-07-12,5615.35009765625
^GSPC,2024-07-15,5631.22021484375
^GSPC,2024-07-16,5667.2001953125
^GSPC,2024-07-17,5588.27001953125
^GSPC,2024-07-18,5544.58984375
^GSPC,2024-07-19,5505
^GSPC,2024-07-22,5564.41015625
^GSPC,2024-07-23,5555.740234375
^GSPC,2024-07-24,5427.1298828125
^GSPC,2024-07-25,5399.22021484375
^GSPC,2024-07-26,5459.10009765625
^GSPC,2024-07-29,5463.5400390625
^GSPC,2024-07-30,5436.43994140625
^GSPC,2024-07-31,5522.2998046875
^GSPC,2024-08-01,5446.68017578125
^GSPC,2024-08-02,5346.56005859375
^GSPC,2024-08-05,5186.330078125
^GSPC,2024-08-06,5240.02978515625
^GSPC,2024-08-07,5199.5
^GSPC,2024-08-08,5319.31005859375
^GSPC,2024-08-09,5344.16015625
^GSPC,2024-08-12,5344.39013671875
^GSPC,2024-08-13,5434.43017578125
^GSPC,2024-08-14,5455.2099609375
^GSPC,2024-08-15,5543.22021484375
^GSPC,2024-08-16,5554.25
^GSPC,2024-08-19,5608.25
^GSPC,2024-08-20,5597.1201171875
^GSPC,2024-08-21,5620.85009765625
^GSPC,2024-08-22,5570.64013671875
^GSPC,2024-08-23,5634.60986328125
^GSPC,2024-08-26,5616.83984375
^GSPC,2024-08-27,5625.7998046875
^GSPC,2024-08-28,5592.18017578125
^GSPC,2024-08-29,5591.9599609375
^GSPC,2024-08-30,5648.39990234375
^GSPC,2024-09-03,5528.93017578125
^GSPC,2024-09-04,5520.06982421875
^GSPC,2024-09-05,5503.41015625
^GSPC,2024-09-06,5408.419921875
^GSPC,2024-09-09,5471.0498046875
^GSPC,2024-09-10,5495.52001953125
^GSPC,2024-09-11,5554.1298828125
^GSPC,2024-09-12,5595.759765625
^GSPC,2024-09-13,5626.02001953125
^GSPC,2024-09-16,5633.08984375
^GSPC,2024-09-17,5634.580078125
^GSPC,2024-09-18,5618.259765625
^GSPC,2024-09-19,5713.64013671875
^GSPC,2024-09-20,5702.5498046875
^GSPC,2024-09-23,5718.56982421875
^GSPC,2024-09-24,5732.93017578125
^GSPC,2024-09-25,5722.259765625
^GSPC,2024-09-26,5745.3701171875
^GSPC,2024-09-27,5738.169921875
^GSPC,2024-09-30,5762.47998046875
^GSPC,2024-10-01,5708.75
^GSPC,2024-10-02,5709.5400390625
^GSPC,2024-10-03,5699.93994140625
^GSPC,2024-10-04,5751.06982421875
^GSPC,2024-10-07,5695.93994140625
^GSPC,2024-10-08,5751.1298828125
^GSPC,2024-10-09,5792.0400390625
^GSPC,2024-10-10,5780.0498046875
^GSPC,2024-10-11,5815.02978515625
^GSPC,2024-10-14,5859.85009765625
^GSPC,2024-10-15,5815.259765625
^GSPC,2024-10-16,5842.47021484375
^GSPC,2024-10-17,5841.47021484375
^GSPC,2024-10-18,5864.669921875
^GSPC,2024-10-21,5853.97998046875
^GSPC,2024-10-22,5851.2001953125
^GSPC,2024-10-23,5797.419921875
^GSPC,2024-10-24,5809.85986328125
^GSPC,2024-10-25,5808.1201171875
^GSPC,2024-10-28,5823.52001953125
^GSPC,2024-10-29,5832.919921875
^GSPC,2024-10-30,5813.669921875
^GSPC,2024-10-31,5705.4501953125
^GSPC,2024-11-01,5728.7998046875
^GSPC,2024-11-04,5712.68994140625
^GSPC,2024-11-05,5782.759765625
^GSPC,2024-11-06,5929.0400390625
^GSPC,2024-11-07,5973.10009765625
^GSPC,2024-11-08,5995.5400390625
^GSPC,2024-11-11,6001.35009765625
^GSPC,2024-11-12,5983.990234375
^GSPC,2024-11-13,5985.3798828125
^GSPC,2024-11-14,5949.169921875
^GSPC,2024-11-15,5870.6201171875
^GSPC,2024-11-18,5893.6201171875
^GSPC,2024-11-19,5916.97998046875
^GSPC,2024-11-20,5917.10986328125
^GSPC,2024-11-21,5948.7099609375
^GSPC,2024-11-22,5969.33984375
^GSPC,2024-11-25,5987.3701171875
^GSPC,2024-11-26,6021.6298828125
^GSPC,2024-11-27,5998.740234375
^GSPC,2024-11-29,6032.3798828125
^GSPC,2024-12-02,6047.14990234375
^GSPC,2024-12-03,6049.8798828125
^GSPC,2024-12-04,6086.490234375
^GSPC,2024-12-05,6075.10986328125
^GSPC,2024-12-06,6090.27001953125
^GSPC,2024-12-09,6052.85009765625
^GSPC,2024-12-10,6034.91015625
^GSPC,2024-12-11,6084.18994140625
^GSPC,2024-12-12,6051.25
^GSPC,2024-12-13,6051.08984375
^GSPC,2024-12-16,6074.080078125
^GSPC,2024-12-17,6050.60986328125
^GSPC,2024-12-18,5872.16015625
^GSPC,2024-12-19,5867.080078125
^GSPC,2024-12-20,5930.85009765625
^GSPC,2024-12-23,5974.06982421875
^GSPC,2024-12-24,6040.0400390625
^GSPC,2024-12-26,6037.58984375
^GSPC,2024-12-27,5970.83984375
^GSPC,2024-12-30,5906.93994140625
^GSPC,2024-12-31,5881.6298828125
^GSPC,2025-01-02,5868.5498046875
^GSPC,2025-01-03,5942.47021484375
^GSPC,2025-01-06,5975.3798828125
^GSPC,2025-01-07,5909.02978515625
^GSPC,2025-01-08,5918.25
^GSPC,2025-01-10,5827.0400390625
^GSPC,2025-01-13,5836.22021484375
^GSPC,2025-01-14,5842.91015625
^GSPC,2025-01-15,5949.91015625
^GSPC,2025-01-16,5937.33984375
^GSPC,2025-01-17,5996.66015625
^GSPC,2025-01-21,6049.240234375
^GSPC,2025-01-22,6086.3701171875
^GSPC,2025-01-23,6118.7099609375
^GSPC,2025-01-24,6101.240234375
^GSPC,2025-01-27,6012.27978515625
^GSPC,2025-01-28,6067.7001953125
^GSPC,2025-01-29,6039.31005859375
^GSPC,2025-01-30,6071.169921875
^GSPC,2025-01-31,6040.52978515625
^GSPC,2025-02-03,5994.56982421875
^GSPC,2025-02-04,6037.8798828125
^GSPC,2025-02-05,6061.47998046875
^GSPC,2025-02-06,6083.56982421875
^GSPC,2025-02-07,6025.990234375
^GSPC,2025-02-10,6066.43994140625
^GSPC,2025-02-11,6068.5
^GSPC,2025-02-12,6051.97021484375
^GSPC,2025-02-13,6115.06982421875
^GSPC,2025-02-14,6114.6298828125
^GSPC,2025-02-18,6129.580078125
^GSPC,2025-02-19,6144.14990234375
^GSPC,2025-02-20,6117.52001953125
^GSPC,2025-02-21,6013.1298828125
^GSPC,2025-02-24,5983.25
^GSPC,2025-02-25,5955.25
^GSPC,2025-02-26,5956.06005859375
^GSPC,2025-02-27,5861.56982421875
^GSPC,2025-02-28,5954.5
^GSPC,2025-03-03,5849.72021484375
^GSPC,2025-03-04,5778.14990234375
^GSPC,2025-03-05,5842.6298828125
^GSPC,2025-03-06,5738.52001953125
^GSPC,2025-03-07,5770.2001953125
^GSPC,2025-03-10,5614.56005859375
^GSPC,2025-03-11,5572.06982421875
^GSPC,2025-03-12,5599.2998046875
^GSPC,2025-03-13,5521.52001953125
^GSPC,2025-03-14,5638.93994140625
^GSPC,2025-03-17,5675.1201171875
^GSPC,2025-03-18,5614.66015625
^GSPC,2025-03-19,5675.2900390625
^GSPC,2025-03-20,5662.89013671875
^GSPC,2025-03-21,5667.56005859375
^GSPC,2025-03-24,5767.56982421875
^GSPC,2025-03-25,5776.64990234375
^GSPC,2025-03-26,5712.2001953125
^GSPC,2025-03-27,5693.31005859375
^GSPC,2025-03-28,5580.93994140625
^GSPC,2025-03-31,5611.85009765625
"""
temp = tempfile.NamedTemporaryFile(delete=False, suffix=".csv", mode='w', newline='')
temp.write(sample_data)
temp.close()
return temp.name
# Global theme
theme = gr.themes.Soft(
primary_hue="blue",
secondary_hue="indigo",
neutral_hue="gray"
)
# Gradio interface
with gr.Blocks(title="Time Series Forecasting App", theme=theme) as app:
gr.Markdown("# 📈 Time Series Forecasting App")
gr.Markdown("Upload a CSV with `unique_id`, `ds`, and `y` columns to apply forecasting models.")
with gr.Row():
with gr.Column(scale=2):
file_input = gr.File(label="Upload CSV file", file_types=[".csv"])
download_btn = gr.Button("Download Sample Data", variant="secondary")
download_output = gr.File(label="Click to download", visible=True)
download_btn.click(fn=download_sample, outputs=download_output)
with gr.Accordion("Data & Validation Settings", open=True):
frequency = gr.Dropdown(
choices=[
("Hourly", "H"),
("Daily", "D"),
("Weekly", "WS"),
("Monthly", "MS"),
("Quarterly", "QS"),
("Yearly", "YS")
],
label="Data Frequency",
value="D"
)
# Evaluation Strategy
eval_strategy = gr.Radio(
choices=["Fixed Window", "Cross Validation"],
label="Evaluation Strategy",
value="Cross Validation"
)
# Fixed Window settings
with gr.Group(visible=True) as fixed_window_box:
gr.Markdown("### Fixed Window Settings")
horizon = gr.Slider(1, 100, value=10, step=1, label="Validation Horizon (steps ahead to predict)")
# Cross Validation settings
with gr.Group(visible=True) as cv_box:
gr.Markdown("### Cross Validation Settings")
with gr.Row():
step_size = gr.Slider(1, 50, value=10, step=1, label="Step Size (distance between windows)")
num_windows = gr.Slider(1, 20, value=5, step=1, label="Number of Windows")
# Future forecast settings (always visible)
with gr.Group():
gr.Markdown("### Future Forecast Settings")
future_horizon = gr.Slider(1, 100, value=10, step=1, label="Future Forecast Horizon (steps to predict)")
with gr.Accordion("Model Configuration", open=True):
gr.Markdown("## Basic Models")
with gr.Row():
use_historical_avg = gr.Checkbox(label="Historical Average", value=True)
use_naive = gr.Checkbox(label="Naive", value=True)
# Common seasonality parameter at the top level
with gr.Group():
gr.Markdown("### Seasonality Configuration")
gr.Markdown("This seasonality period affects Seasonal Naive, Seasonal Window Average, AutoETS, and AutoARIMA models")
seasonality = gr.Number(label="Seasonality Period", value=5)
gr.Markdown("### Seasonal Models")
with gr.Row():
use_seasonal_naive = gr.Checkbox(label="Seasonal Naive", value=True)
gr.Markdown("### Window-based Models")
with gr.Row():
use_window_avg = gr.Checkbox(label="Window Average", value=True)
window_size = gr.Number(label="Window Size", value=10)
with gr.Row():
use_seasonal_window_avg = gr.Checkbox(label="Seasonal Window Average", value=True)
seasonal_window_size = gr.Number(label="Seasonal Window Size", value=2)
gr.Markdown("### Advanced Models (use seasonality from above)")
with gr.Row():
use_autoets = gr.Checkbox(label="AutoETS (Exponential Smoothing)", value=True)
use_autoarima = gr.Checkbox(label="AutoARIMA", value=True)
with gr.Column(scale=3):
message_output = gr.Textbox(label="Status Message")
with gr.Tabs() as tabs:
with gr.TabItem("Validation Results"):
eval_output = gr.Dataframe(label="Evaluation Metrics")
validation_plot = gr.Plot(label="Validation Plot")
validation_output = gr.Dataframe(label="Validation Data", visible=False)
with gr.Row():
show_data_btn = gr.Button("Show Validation Data")
hide_data_btn = gr.Button("Hide Validation Data", visible=False)
def show_data():
return gr.update(visible=True), gr.update(visible=True), gr.update(visible=False)
def hide_data():
return gr.update(visible=False), gr.update(visible=False), gr.update(visible=True)
show_data_btn.click(
fn=show_data,
outputs=[validation_output, hide_data_btn, show_data_btn]
)
hide_data_btn.click(
fn=hide_data,
outputs=[validation_output, hide_data_btn, show_data_btn]
)
with gr.TabItem("Future Forecast"):
forecast_plot = gr.Plot(label="Future Forecast Plot")
forecast_output = gr.Dataframe(label="Future Forecast Data", visible=False)
with gr.Row():
show_forecast_btn = gr.Button("Show Forecast Data")
hide_forecast_btn = gr.Button("Hide Forecast Data", visible=False)
def show_forecast():
return gr.update(visible=True), gr.update(visible=True), gr.update(visible=False)
def hide_forecast():
return gr.update(visible=False), gr.update(visible=False), gr.update(visible=True)
show_forecast_btn.click(
fn=show_forecast,
outputs=[forecast_output, hide_forecast_btn, show_forecast_btn]
)
hide_forecast_btn.click(
fn=hide_forecast,
outputs=[forecast_output, hide_forecast_btn, show_forecast_btn]
)
with gr.TabItem("Export Results"):
export_files = gr.Files(label="Download Results")
with gr.Row(visible=True) as run_row:
submit_btn = gr.Button("Run Validation and Forecast", variant="primary", size="lg")
# Update visibility of the appropriate box based on evaluation strategy
def update_eval_boxes(strategy):
return (gr.update(visible=strategy == "Fixed Window"),
gr.update(visible=strategy == "Cross Validation"))
eval_strategy.change(
fn=update_eval_boxes,
inputs=[eval_strategy],
outputs=[fixed_window_box, cv_box]
)
# Run forecast when button is clicked
submit_btn.click(
fn=run_forecast,
inputs=[
file_input, frequency, eval_strategy, horizon, step_size, num_windows,
use_historical_avg, use_naive, use_seasonal_naive, seasonality,
use_window_avg, window_size, use_seasonal_window_avg, seasonal_window_size,
use_autoets, use_autoarima, future_horizon
],
outputs=[eval_output, validation_output, validation_plot, forecast_output, forecast_plot, export_files, message_output]
)
if __name__ == "__main__":
app.launch(share=False)