|
import streamlit as st |
|
import pandas as pd |
|
from io import BytesIO |
|
from itertools import product |
|
from statsmodels.tsa.holtwinters import ExponentialSmoothing |
|
import plotly.express as px |
|
|
|
|
|
def run_exp_smoothing(city_data, trend, damped_trend, seasonal, seasonal_period): |
|
try: |
|
model = ExponentialSmoothing(city_data, trend=trend, damped_trend=damped_trend, seasonal=seasonal, seasonal_periods=seasonal_period) |
|
model_fit = model.fit(optimized=True) |
|
return model_fit.forecast(steps=6), model_fit.aic |
|
except Exception as e: |
|
st.error(f"An error occurred during model fitting: {e}") |
|
return None, None |
|
|
|
def create_data(): |
|
data = pd.read_csv('accident_count.csv', parse_dates=True, index_col=0) |
|
data.index = pd.to_datetime(data.index, format='%Y%m') |
|
data = data.groupby('City').resample('M').sum().reset_index() |
|
data.index = data['Accident Month Bracket'] |
|
data = data.drop(['Accident Month Bracket'],axis=1) |
|
data.index = data.index.strftime('%Y-%m') |
|
return data |
|
|
|
|
|
def to_excel(df): |
|
output = BytesIO() |
|
writer = pd.ExcelWriter(output, engine='xlsxwriter') |
|
df.to_excel(writer, sheet_name='Sheet1') |
|
writer.save() |
|
processed_data = output.getvalue() |
|
return processed_data |
|
|
|
|
|
if 'best_params' not in st.session_state: |
|
st.session_state.best_params = {'trend': None, 'damped_trend': False, 'seasonal': None, 'seasonal_period': 12} |
|
|
|
st.title("Exponential Smoothing Forecasting") |
|
|
|
|
|
data = create_data() |
|
unique_cities = data['City'].unique() |
|
|
|
|
|
tabs = st.tabs(unique_cities) |
|
for tab, city in zip(tabs, unique_cities): |
|
with tab: |
|
|
|
trend = st.select_slider('Select Trend', options=['add', 'mul', None], value=st.session_state.best_params['trend']) |
|
damped_trend = False |
|
seasonal = st.select_slider('Select Seasonal', options=['add', 'mul', None], value=st.session_state.best_params['seasonal']) |
|
seasonal_period = st.slider('Seasonal Period', 1, 24, value=st.session_state.best_params['seasonal_period']) |
|
|
|
city_data = data[data['City'] == city]['Accident Count'] |
|
forecast, aic = run_exp_smoothing(city_data, trend, damped_trend, seasonal, seasonal_period) |
|
|
|
if forecast is not None: |
|
st.write(f"Best Parameters with AIC: {aic}") |
|
st.write(f"Trend: {trend}, Damped Trend: {damped_trend}, Seasonal: {seasonal}, Seasonal Period: {seasonal_period}") |
|
forecast_index = pd.date_range(start=city_data.index[-1], periods=7, freq='M')[1:] |
|
forecast_index = forecast_index.to_period('M') |
|
forecast_df = pd.DataFrame(forecast, columns=['Forecast']) |
|
forecast_df = forecast_df.round(0) |
|
st.table(forecast_df) |
|
fig = px.line(forecast_df, x=forecast_df.index, y="Forecast") |
|
st.plotly_chart(fig) |
|
|
|
|
|
if st.button(f'Run Grid Search for {city}'): |
|
best_aic = float('inf') |
|
best_params = None |
|
for param_set in product(['add', 'mul', None], [False], ['add', 'mul', None], [12]): |
|
_, temp_aic = run_exp_smoothing(city_data, *param_set) |
|
if temp_aic and temp_aic < best_aic: |
|
best_aic = temp_aic |
|
best_params = param_set |
|
|
|
|
|
st.session_state.best_params = { |
|
'trend': best_params[0], |
|
'damped_trend': best_params[1], |
|
'seasonal': best_params[2], |
|
'seasonal_period': best_params[3] |
|
} |
|
st.write(f"Best Parameters for {city}: {best_params} with AIC: {best_aic}") |
|
|
|
|
|
|
|
if st.button(f'Export {city} to Excel'): |
|
df_to_export = forecast_df |
|
excel_data = to_excel(df_to_export) |
|
st.download_button(label='π₯ Download Excel', data=excel_data, file_name=f'{city}_forecast.xlsx', mime='application/vnd.ms-excel') |