Spaces:
Sleeping
Sleeping
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) |