Spaces:
Sleeping
Sleeping
Download src/forecaster.py from ranbyDipz/BTP-Intelligence-Engine: direct link, hf CLI and curl.
- Browser
- Download file 3.62 kB
-
https://huggingface.co/spaces/ranbyDipz/BTP-Intelligence-Engine/resolve/main/src/forecaster.py
- Command line
-
hf download hf://spaces/ranbyDipz/BTP-Intelligence-Engine/src/forecaster.py
-
curl -L -o forecaster.py https://huggingface.co/spaces/ranbyDipz/BTP-Intelligence-Engine/resolve/main/src/forecaster.py
3.62 kB
| import pandas as pd | |
| import numpy as np | |
| from sklearn.model_selection import train_test_split | |
| from sklearn.preprocessing import LabelEncoder | |
| import xgboost as xgb | |
| import joblib | |
| import os | |
| import warnings | |
| warnings.filterwarnings('ignore') | |
| class ImpactForecaster: | |
| def __init__(self): | |
| self.model = xgb.XGBRegressor( | |
| n_estimators=150, | |
| learning_rate=0.1, | |
| max_depth=6, | |
| random_state=42 | |
| ) | |
| self.encoders = {} | |
| self.features = ['latitude', 'longitude', 'event_type_encoded', | |
| 'event_cause_encoded', 'priority_encoded', | |
| 'start_hour', 'day_of_week', 'is_weekend'] | |
| self.is_trained = False | |
| def train(self, df): | |
| """Trains the XGBoost model to predict impact duration.""" | |
| print("Training ImpactForecaster...") | |
| cat_cols = ['event_type', 'event_cause', 'priority'] | |
| df_encoded = df.copy() | |
| for col in cat_cols: | |
| le = LabelEncoder() | |
| df_encoded[col] = df_encoded[col].astype(str) | |
| le.fit(df_encoded[col].tolist() + ['unknown']) | |
| self.encoders[col] = le | |
| df_encoded[col + '_encoded'] = le.transform(df_encoded[col]) | |
| X = df_encoded[self.features] | |
| y = np.log1p(df_encoded['impact_duration_mins']) | |
| X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) | |
| self.model.fit( | |
| X_train, y_train, | |
| eval_set=[(X_test, y_test)], | |
| verbose=False | |
| ) | |
| self.is_trained = True | |
| # Save model | |
| os.makedirs('models', exist_ok=True) | |
| joblib.dump(self.model, 'models/forecaster_model.pkl') | |
| joblib.dump(self.encoders, 'models/forecaster_encoders.pkl') | |
| print("Model training complete and saved.") | |
| def predict(self, event_data): | |
| """Predicts impact duration and calculates congestion radius.""" | |
| if not self.is_trained: | |
| self._load_model() | |
| df = pd.DataFrame([event_data]) | |
| for col, le in self.encoders.items(): | |
| if col in df.columns: | |
| val = str(df[col].iloc[0]) | |
| if val not in le.classes_: | |
| val = 'unknown' | |
| df[col + '_encoded'] = le.transform([val]) | |
| else: | |
| df[col + '_encoded'] = le.transform(['unknown']) | |
| for feat in self.features: | |
| if feat not in df.columns: | |
| df[feat] = 0 | |
| X = df[self.features] | |
| log_pred = self.model.predict(X)[0] | |
| duration_mins = np.expm1(log_pred) | |
| # Congestion radius scales with duration and priority | |
| base_radius = 500 | |
| priority_val = str(event_data.get('priority', '')).lower() | |
| if priority_val == 'high': | |
| base_radius = 800 | |
| elif priority_val == 'low': | |
| base_radius = 300 | |
| congestion_radius = min(base_radius + (duration_mins * 6), 4000) | |
| return { | |
| 'predicted_duration_mins': float(duration_mins), | |
| 'congestion_radius_meters': float(congestion_radius) | |
| } | |
| def _load_model(self): | |
| try: | |
| self.model = joblib.load('models/forecaster_model.pkl') | |
| self.encoders = joblib.load('models/forecaster_encoders.pkl') | |
| self.is_trained = True | |
| except FileNotFoundError: | |
| raise RuntimeError("Model not trained yet. Call train() first.") | |