import pandas as pd import numpy as np from sklearn.ensemble import GradientBoostingRegressor from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score, mean_absolute_percentage_error from sklearn.model_selection import GridSearchCV import joblib import sys import io import warnings warnings.filterwarnings('ignore') # Set standard output and standard error to UTF-8 to prevent Unicode encoding errors on Windows if sys.platform == 'win32': sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8') print("🚀 MEMULAI PROSES TRAINING AI LEVEL ADVANCED (ECO-TWIN PRO)...\n") # ========================================== # 1. LOAD LOCALIZED DATA # ========================================== print("1. Menarik & Memproses Data Historis Lokal...") df = pd.read_csv('dataset_local_2026.csv') df['Tanggal'] = pd.to_datetime(df['Tanggal']) # Baseline Sampah (Diambil dari SIPSN DKI 2025) base_sampah = 8020.0 mrt_harian_avg = 85000 hujan_mean = 10.5 # Data Event data_event_csv = """Tanggal,Nama_Event,Ada_Event 2023-01-01,Tahun Baru 2023,1 2023-03-11,Konser BLACKPINK,1 2023-03-12,Konser BLACKPINK,1 2023-05-26,Java Jazz,1 2023-06-19,Timnas Argentina,1 2023-11-15,Coldplay,1 2023-12-31,Tahun Baru 2024,1 2024-01-01,Tahun Baru 2024,1 2024-03-02,Ed Sheeran,1 2024-05-24,Java Jazz 2024,1 2024-12-31,Malam Tahun Baru 2025,1""" df_event = pd.read_csv(io.StringIO(data_event_csv)) df_event['Tanggal'] = pd.to_datetime(df_event['Tanggal']) # Bikin Master Kalender 2 Tahun (Lebih banyak data, AI makin pintar) df = pd.DataFrame({'Tanggal': pd.date_range(start="2023-01-01", end="2024-12-31")}) df = pd.merge(df, df_event[['Tanggal', 'Ada_Event']], on='Tanggal', how='left').fillna({'Ada_Event': 0}) # Simulasi Pola Realistis df['Penumpang_MRT'] = np.random.normal(loc=mrt_harian_avg, scale=mrt_harian_avg*0.15, size=len(df)).astype(int) df['Curah_Hujan_mm'] = np.random.exponential(scale=hujan_mean, size=len(df)) df.loc[df['Curah_Hujan_mm'] < 2, 'Curah_Hujan_mm'] = 0 # ========================================== # 2. FEATURE ENGINEERING (LOCAL BINDING) # ========================================== print("2. Melakukan One-Hot Encoding Lokasi & Verifikasi Fitur...") # Defensive manual one-hot encoding to guarantee column names and order locations = ['JIS', 'GBK', 'Pasar Senen', 'Gang Sempit Tambora'] for loc in locations: df[f'Loc_{loc}'] = (df['Location'] == loc).astype(int) # Fitur yang dipakai AI buat berpikir fitur = [ 'Loc_JIS', 'Loc_GBK', 'Loc_Pasar Senen', 'Loc_Gang Sempit Tambora', 'RR', 'Rain_Lag_1', 'Rain_Lag_2', 'Is_Holiday', 'Ada_Event', 'Crowd_Scale', 'Hari_Ke', 'Is_Weekend', 'Hari_Dalam_Minggu', 'Bulan' ] X = df[fitur] y = df['Volume_Ton'] # ========================================== # 3. CHRONOLOGICAL SPLIT & TRAINING # ========================================== print("3. Membagi Data secara Kronologis (75/25) & Melatih Model...") # 75% days for training, 25% for test. # Since we have 4 locations per day, we split at index: (len(df) // 4 * 0.75) * 4 num_days = len(df) // 4 train_days = int(num_days * 0.75) train_size = train_days * 4 X_train, X_test = X.iloc[:train_size], X.iloc[train_size:] y_train, y_test = y.iloc[:train_size], y.iloc[train_size:] # Menggunakan Gradient Boosting Regressor (Baseline) print("⚙️ Melatih model Baseline...") base_model = GradientBoostingRegressor( n_estimators=200, learning_rate=0.1, max_depth=4, random_state=42 ) base_model.fit(X_train, y_train) pred_base = base_model.predict(X_test) # Hitung Metrics Baseline mae_base = mean_absolute_error(y_test, pred_base) rmse_base = mean_squared_error(y_test, pred_base) ** 0.5 r2_base = r2_score(y_test, pred_base) mape_base = mean_absolute_percentage_error(y_test, pred_base) * 100 # ========================================== # 4. HYPERPARAMETER TUNING (UPGRADE MODEL) # ========================================== print("\n⚙️ Melakukan Hyperparameter Tuning menggunakan GridSearchCV...") param_grid = { 'n_estimators': [100, 200, 300], 'learning_rate': [0.03, 0.05, 0.1, 0.15], 'max_depth': [3, 4, 5], 'subsample': [0.8, 0.9, 1.0] } grid_search = GridSearchCV( estimator=GradientBoostingRegressor(random_state=42), param_grid=param_grid, cv=3, scoring='neg_mean_absolute_error', n_jobs=-1, verbose=1 ) grid_search.fit(X_train, y_train) best_model = grid_search.best_estimator_ pred_best = best_model.predict(X_test) # Hitung Metrics Upgraded Model mae_best = mean_absolute_error(y_test, pred_best) rmse_best = mean_squared_error(y_test, pred_best) ** 0.5 r2_best = r2_score(y_test, pred_best) mape_best = mean_absolute_percentage_error(y_test, pred_best) * 100 # ========================================== # 5. PERBANDINGAN METRICS (BUAT DIPAMERIN KE JURI) # ========================================== print("\n📊 HASIL EVALUASI & PERBANDINGAN METRICS:") print(f"┌─────────────────────────┬──────────────────────┬──────────────────────┬──────────────────────┐") print(f"│ Metric │ Baseline Model │ Upgraded Model │ Status │") print(f"├─────────────────────────┼──────────────────────┼──────────────────────┼──────────────────────┤") print(f"│ Mean Absolute Error │ {mae_base:16.2f} Ton │ {mae_best:16.2f} Ton │ {'Semakin Baik (⬇️)' if mae_best < mae_base else 'Sama/Stabil'} │") print(f"│ Root Mean Squared Error │ {rmse_base:16.2f} Ton │ {rmse_best:16.2f} Ton │ {'Semakin Baik (⬇️)' if rmse_best < rmse_base else 'Sama/Stabil'} │") print(f"│ R-Squared (R² Score) │ {r2_base*100:15.2f}% │ {r2_best*100:15.2f}% │ {'Semakin Baik (⬆️)' if r2_best > r2_base else 'Sama/Stabil'} │") print(f"│ MAPE (Error Persentase) │ {mape_base:15.2f}% │ {mape_best:15.2f}% │ {'Semakin Baik (⬇️)' if mape_best < mape_base else 'Sama/Stabil'} │") print(f"└─────────────────────────┴──────────────────────┴──────────────────────┴──────────────────────┘") print(f"\n⚙️ Hyperparameter Terbaik hasil tuning:") print(f" - n_estimators : {grid_search.best_params_['n_estimators']}") print(f" - learning_rate: {grid_search.best_params_['learning_rate']}") print(f" - max_depth : {grid_search.best_params_['max_depth']}") print(f" - subsample : {grid_search.best_params_['subsample']}") # Cek Fitur Paling Berpengaruh importances = best_model.feature_importances_ print("\n🌟 FITUR PALING BERPENGARUH PADA TIMBULAN SAMPAH (UPGRADED):") for name, importance in zip(fitur, importances): print(f" - {name}: {importance*100:.1f}%") # Simpan Model Terbaik joblib.dump(best_model, 'model_sampah_advanced.pkl') print("\n💾 SUCCESS! 'model_sampah_advanced.pkl' berhasil di-generate menggunakan model hasil upgrade!")