Upload folder using huggingface_hub
Browse files- .gitattributes +2 -0
- congestion_multiplier_v1.cbm +3 -0
- train_traffic_mult.py +159 -0
- training_diagnostics.png +3 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
congestion_multiplier_v1.cbm filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
training_diagnostics.png filter=lfs diff=lfs merge=lfs -text
|
congestion_multiplier_v1.cbm
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:477a52f47bab33557f78432575b90cf1d5a606084484a34543569156d848f297
|
| 3 |
+
size 3552656
|
train_traffic_mult.py
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import numpy as np
|
| 3 |
+
import pandas as pd
|
| 4 |
+
from catboost import CatBoostRegressor, Pool
|
| 5 |
+
from sklearn.model_selection import train_test_split, KFold
|
| 6 |
+
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
|
| 7 |
+
import matplotlib.pyplot as plt
|
| 8 |
+
|
| 9 |
+
# βββ 1. LOAD βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 10 |
+
df = pd.read_csv('data/raw/lahore_traffic_dataset.csv')
|
| 11 |
+
print(f"Loaded: {df.shape[0]} rows Γ {df.shape[1]} cols")
|
| 12 |
+
print(df.dtypes)
|
| 13 |
+
print(df.head(3).to_string())
|
| 14 |
+
|
| 15 |
+
# βββ 2. VALIDATE βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 16 |
+
assert df['congestion_multiplier'].between(0.55, 3.5).all(), "Target out of range!"
|
| 17 |
+
assert (df['origin_zone'] != df['dest_zone']).all(), "Self-loops in data!"
|
| 18 |
+
assert df.isnull().sum().sum() == 0, "Null values found!"
|
| 19 |
+
print(f"\nβ
Validation passed")
|
| 20 |
+
print(f"Target range: {df['congestion_multiplier'].min():.3f} β {df['congestion_multiplier'].max():.3f}")
|
| 21 |
+
print(f"Target mean: {df['congestion_multiplier'].mean():.3f}")
|
| 22 |
+
print(f"Target std: {df['congestion_multiplier'].std():.3f}")
|
| 23 |
+
|
| 24 |
+
# βββ 3. FEATURES βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 25 |
+
TARGET = 'congestion_multiplier'
|
| 26 |
+
|
| 27 |
+
CAT_FEATURES = [
|
| 28 |
+
'origin_zone', 'dest_zone', 'road_type',
|
| 29 |
+
'is_one_way', 'has_signal', 'is_construction',
|
| 30 |
+
'weather_condition', 'day_of_week', 'time_slot',
|
| 31 |
+
'is_weekend', 'is_holiday', 'day_type'
|
| 32 |
+
]
|
| 33 |
+
|
| 34 |
+
NUM_FEATURES = [
|
| 35 |
+
'speed_limit_kmh', 'num_lanes', 'distance_km', 'road_curvature'
|
| 36 |
+
]
|
| 37 |
+
|
| 38 |
+
# Cast categoricals to str so CatBoost handles them correctly
|
| 39 |
+
for col in CAT_FEATURES:
|
| 40 |
+
df[col] = df[col].astype(str)
|
| 41 |
+
|
| 42 |
+
X = df[CAT_FEATURES + NUM_FEATURES]
|
| 43 |
+
y = df[TARGET]
|
| 44 |
+
|
| 45 |
+
print(f"\nFeatures: {list(X.columns)}")
|
| 46 |
+
print(f"Cat: {CAT_FEATURES}")
|
| 47 |
+
print(f"Num: {NUM_FEATURES}")
|
| 48 |
+
|
| 49 |
+
# βββ 4. SPLIT ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 50 |
+
X_train, X_test, y_train, y_test = train_test_split(
|
| 51 |
+
X, y, test_size=0.15, random_state=42
|
| 52 |
+
)
|
| 53 |
+
X_train, X_val, y_train, y_val = train_test_split(
|
| 54 |
+
X_train, y_train, test_size=0.15, random_state=42
|
| 55 |
+
)
|
| 56 |
+
|
| 57 |
+
print(f"\nTrain: {len(X_train)} | Val: {len(X_val)} | Test: {len(X_test)}")
|
| 58 |
+
|
| 59 |
+
train_pool = Pool(X_train, y_train, cat_features=CAT_FEATURES)
|
| 60 |
+
val_pool = Pool(X_val, y_val, cat_features=CAT_FEATURES)
|
| 61 |
+
test_pool = Pool(X_test, y_test, cat_features=CAT_FEATURES)
|
| 62 |
+
|
| 63 |
+
# βββ 5. TRAIN ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 64 |
+
model = CatBoostRegressor(
|
| 65 |
+
iterations=2000,
|
| 66 |
+
learning_rate=0.04,
|
| 67 |
+
depth=8,
|
| 68 |
+
l2_leaf_reg=3,
|
| 69 |
+
min_data_in_leaf=10,
|
| 70 |
+
loss_function='RMSE',
|
| 71 |
+
eval_metric='RMSE',
|
| 72 |
+
random_seed=42,
|
| 73 |
+
verbose=200,
|
| 74 |
+
)
|
| 75 |
+
|
| 76 |
+
model.fit(
|
| 77 |
+
train_pool,
|
| 78 |
+
eval_set=val_pool,
|
| 79 |
+
early_stopping_rounds=100,
|
| 80 |
+
)
|
| 81 |
+
|
| 82 |
+
# βββ 6. EVALUATE βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 83 |
+
def evaluate(pool, y_true, split_name):
|
| 84 |
+
preds = model.predict(pool)
|
| 85 |
+
mae = mean_absolute_error(y_true, preds)
|
| 86 |
+
rmse = np.sqrt(mean_squared_error(y_true, preds))
|
| 87 |
+
r2 = r2_score(y_true, preds)
|
| 88 |
+
mape = np.mean(np.abs((y_true - preds) / y_true)) * 100
|
| 89 |
+
print(f"\nββ {split_name} ββ")
|
| 90 |
+
print(f" MAE : {mae:.4f}")
|
| 91 |
+
print(f" RMSE : {rmse:.4f}")
|
| 92 |
+
print(f" RΒ² : {r2:.4f}")
|
| 93 |
+
print(f" MAPE : {mape:.2f}%")
|
| 94 |
+
return preds
|
| 95 |
+
|
| 96 |
+
print("\n=== EVALUATION ===")
|
| 97 |
+
val_preds = evaluate(val_pool, y_val, "Validation")
|
| 98 |
+
test_preds = evaluate(test_pool, y_test, "Test")
|
| 99 |
+
|
| 100 |
+
# βββ 7. SANITY CHECKS ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 101 |
+
print("\n=== SANITY CHECKS ===")
|
| 102 |
+
|
| 103 |
+
# Check model learned zone personalities
|
| 104 |
+
test_df = X_test.copy()
|
| 105 |
+
test_df['actual'] = y_test.values
|
| 106 |
+
test_df['pred'] = test_preds
|
| 107 |
+
|
| 108 |
+
print("\nMean predicted multiplier by time_slot:")
|
| 109 |
+
print(test_df.groupby('time_slot')['pred'].mean().sort_values(ascending=False).to_string())
|
| 110 |
+
|
| 111 |
+
print("\nMean predicted multiplier by road_type:")
|
| 112 |
+
print(test_df.groupby('road_type')['pred'].mean().sort_values(ascending=False).to_string())
|
| 113 |
+
|
| 114 |
+
print("\nMean predicted multiplier by day_type:")
|
| 115 |
+
print(test_df.groupby('day_type')['pred'].mean().sort_values(ascending=False).to_string())
|
| 116 |
+
|
| 117 |
+
print("\nMean predicted multiplier by weather_condition:")
|
| 118 |
+
print(test_df.groupby('weather_condition')['pred'].mean().sort_values(ascending=False).to_string())
|
| 119 |
+
|
| 120 |
+
# βββ 8. FEATURE IMPORTANCE βββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 121 |
+
fi = pd.Series(
|
| 122 |
+
model.get_feature_importance(),
|
| 123 |
+
index=CAT_FEATURES + NUM_FEATURES
|
| 124 |
+
).sort_values(ascending=False)
|
| 125 |
+
|
| 126 |
+
print("\n=== FEATURE IMPORTANCE ===")
|
| 127 |
+
print(fi.to_string())
|
| 128 |
+
|
| 129 |
+
# βββ 9. PLOTS ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 130 |
+
fig, axes = plt.subplots(1, 3, figsize=(18, 5))
|
| 131 |
+
|
| 132 |
+
# Actual vs predicted
|
| 133 |
+
axes[0].scatter(y_test, test_preds, alpha=0.3, s=10)
|
| 134 |
+
axes[0].plot([0.55, 3.5], [0.55, 3.5], 'r--')
|
| 135 |
+
axes[0].set_xlabel('Actual')
|
| 136 |
+
axes[0].set_ylabel('Predicted')
|
| 137 |
+
axes[0].set_title('Actual vs Predicted')
|
| 138 |
+
|
| 139 |
+
# Residuals
|
| 140 |
+
residuals = y_test.values - test_preds
|
| 141 |
+
axes[1].hist(residuals, bins=50, edgecolor='black')
|
| 142 |
+
axes[1].axvline(0, color='red', linestyle='--')
|
| 143 |
+
axes[1].set_xlabel('Residual')
|
| 144 |
+
axes[1].set_title('Residual Distribution')
|
| 145 |
+
|
| 146 |
+
# Feature importance
|
| 147 |
+
fi.head(12).plot(kind='barh', ax=axes[2])
|
| 148 |
+
axes[2].invert_yaxis()
|
| 149 |
+
axes[2].set_title('Feature Importance')
|
| 150 |
+
|
| 151 |
+
plt.tight_layout()
|
| 152 |
+
plt.savefig('models/training_diagnostics.png', dpi=150)
|
| 153 |
+
plt.show()
|
| 154 |
+
|
| 155 |
+
# βββ 10. SAVE ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 156 |
+
os.makedirs('models', exist_ok=True)
|
| 157 |
+
model.save_model('models/congestion_multiplier_v1.cbm')
|
| 158 |
+
print("\nβ
Model saved β models/congestion_multiplier_v1.cbm")
|
| 159 |
+
|
training_diagnostics.png
ADDED
|
Git LFS Details
|