import pandas as pd import numpy as np from sklearn.linear_model import RidgeCV, LassoCV from sklearn.preprocessing import StandardScaler from sklearn.pipeline import Pipeline from sklearn.metrics import r2_score, mean_absolute_error, mean_squared_error from sklearn.ensemble import RandomForestRegressor from xgboost import XGBRegressor import warnings import os warnings.filterwarnings('ignore') class EmissionForecaster: def __init__(self, data_path='new_daily_emissions_column_format.xlsx'): self.data_path = data_path self.target_col = 'Total Emissions' self.sector_cols = ['Aviation (%)', 'Ground Transport (%)', 'Industry (%)', 'Power (%)', 'Residential (%)'] self.performance_metrics = {} if os.path.exists(data_path): self._train_model() def _create_features(self, df): df = df.copy() df = df.dropna(subset=['Date', self.target_col]) df = df.sort_values('Date').reset_index(drop=True) # 1. Trend & Cyclical Features df['time_index'] = np.arange(len(df)) df['month_sin'] = np.sin(2 * np.pi * df['Date'].dt.month / 12) df['month_cos'] = np.cos(2 * np.pi * df['Date'].dt.month / 12) df['dow_sin'] = np.sin(2 * np.pi * df['Date'].dt.dayofweek / 7) df['dow_cos'] = np.cos(2 * np.pi * df['Date'].dt.dayofweek / 7) # 2. Optimized Lags & Rolling for lag in [1, 7]: df[f'lag_{lag}'] = df[self.target_col].shift(lag) df['roll_mean_7'] = df[self.target_col].shift(1).rolling(window=7).mean() return df.dropna().reset_index(drop=True) def _train_model(self): df_raw = pd.read_excel(self.data_path) df_raw['Date'] = pd.to_datetime(df_raw['Date'], dayfirst=True) self.avg_sectors = df_raw[self.sector_cols].mean().to_dict() df_feat = self._create_features(df_raw) self.df_features = df_feat # Consistent feature set self.feature_cols = ['time_index', 'month_sin', 'month_cos', 'dow_sin', 'dow_cos', 'lag_1', 'lag_7', 'roll_mean_7'] X = df_feat[self.feature_cols].values y = df_feat[self.target_col].values # 80-20 Split split_idx = int(len(X) * 0.80) X_train, X_test = X[:split_idx], X[split_idx:] y_train, y_test = y[:split_idx], y[split_idx:] # Base Models with High Regularization base_models = [ ('lasso', LassoCV(cv=5)), ('rf', RandomForestRegressor(n_estimators=100, max_depth=2, random_state=42)), ('xgb', XGBRegressor(n_estimators=100, max_depth=1, learning_rate=0.05, reg_lambda=100, random_state=42)) ] train_preds, test_preds, trained_pipes = [], [], [] for name, model in base_models: pipe = Pipeline([('scaler', StandardScaler()), ('model', model)]) pipe.fit(X_train, y_train) trained_pipes.append(pipe) train_preds.append(pipe.predict(X_train)) test_preds.append(pipe.predict(X_test)) # Meta-model (RidgeCV auto-tunes the best regularization) meta_model = RidgeCV(alphas=[10, 50, 100, 200, 500]) meta_model.fit(np.column_stack(train_preds), y_train) self.model = {'base': trained_pipes, 'meta': meta_model} # Full Performance Evaluation y_tr_pred = meta_model.predict(np.column_stack(train_preds)) y_ts_pred = meta_model.predict(np.column_stack(test_preds)) self.performance_metrics = { 'train': { 'r2': round(r2_score(y_train, y_tr_pred), 4), 'mae': round(mean_absolute_error(y_train, y_tr_pred), 4), 'rmse': round(np.sqrt(mean_squared_error(y_train, y_tr_pred)), 4) }, 'test': { 'r2': round(r2_score(y_test, y_ts_pred), 4), 'mae': round(mean_absolute_error(y_test, y_ts_pred), 4), 'rmse': round(np.sqrt(mean_squared_error(y_test, y_ts_pred)), 4) } } def forecast_days(self, n_days): recent_emissions = self.df_features[self.target_col].values.tolist() last_date = self.df_features['Date'].iloc[-1] last_idx = self.df_features['time_index'].iloc[-1] forecasts = [] for i in range(1, n_days + 1): f_date = last_date + pd.Timedelta(days=i) feat_vals = [ last_idx + i, # time_index np.sin(2 * np.pi * f_date.month / 12), np.cos(2 * np.pi * f_date.month / 12), np.sin(2 * np.pi * f_date.dayofweek / 7), np.cos(2 * np.pi * f_date.dayofweek / 7), recent_emissions[-1], recent_emissions[-7], np.mean(recent_emissions[-7:]) ] X_ptr = np.array(feat_vals).reshape(1, -1) base_p = [m.predict(X_ptr)[0] for m in self.model['base']] pred = self.model['meta'].predict(np.array(base_p).reshape(1, -1))[0] recent_emissions.append(pred) sects = {k.replace(' (%)','').replace(' ','_'): round(pred * v / 100, 4) for k, v in self.avg_sectors.items()} forecasts.append({'Date': f_date, 'Total_Emission': round(pred, 4), **sects}) return pd.DataFrame(forecasts) if __name__ == "__main__": obj = EmissionForecaster() # 1. Full Performance Table m = obj.performance_metrics print("\n" + " COMPLETE MODEL PERFORMANCE ".center(60, "=")) print(f"{'Metric':<15} | {'Training Set':<15} | {'Test Set':<15}") print("-" * 60) print(f"{'R2 Score':<15} | {m['train']['r2']:<15} | {m['test']['r2']:<15}") print(f"{'MAE':<15} | {m['train']['mae']:<15} | {m['test']['mae']:<15}") print(f"{'RMSE':<15} | {m['train']['rmse']:<15} | {m['test']['rmse']:<15}") print("="*60) # 2. Generate and Split CSVs days = 1096 # 2026-2028 print(f"\nGenerating and splitting forecast for {days} days...") forecast_df = obj.forecast_days(days) # Save Full View (Predicted only) full_csv = forecast_df.copy() full_csv['Date'] = full_csv['Date'].dt.strftime('%Y-%m-%d') full_csv.to_csv("emission_forecast_3years_full.csv", index=False) print("1. Saved: emission_forecast_3years_full.csv") # Save Individual Years for yr in [2026, 2027, 2028]: year_data = forecast_df[forecast_df['Date'].dt.year == yr].copy() year_data['Date'] = year_data['Date'].dt.strftime('%Y-%m-%d') year_data = year_data[['Date', 'Total_Emission', 'Aviation', 'Ground_Transport', 'Industry', 'Power', 'Residential']] year_data.to_csv(f"emission_forecast_{yr}.csv", index=False) print(f" Generated: emission_forecast_{yr}.csv") print("\n" + " SUCCESS: ALL FILES SAVED ".center(60, "="))