mumbai-crowd-predictor / src /risk_engine.py
harshit-temkar7-ds
Initial commit - Mumbai Train Project
75c2779
Raw History Blame Contribute Delete
5.5 kB
"""
Advanced Risk Engine - Explains crowd predictions with reasoning and recommendations
"""
from typing import Dict, List
RISK_CONFIG = {
"Low": {
"score": 15,
"color": "#10b981",
"bg": "#d1fae5",
"emoji": "🟒",
"badge": "LOW RISK",
"advice": "Comfortable travel expected. Enjoy your journey!",
},
"Medium": {
"score": 50,
"color": "#f59e0b",
"bg": "#fef3c7",
"emoji": "🟑",
"badge": "MODERATE",
"advice": "Moderate crowd. Book window seat in advance if possible.",
},
"Extreme": {
"score": 90,
"color": "#ef4444",
"bg": "#fee2e2",
"emoji": "πŸ”΄",
"badge": "EXTREME",
"advice": "Very crowded! Consider alternate timing or route.",
},
}
HOUR_LABELS = {
5: "Early Morning", 6: "Early Morning",
7: "Morning Rush", 8: "Peak Morning Rush", 9: "Morning Rush",
10: "Mid Morning", 11: "Late Morning",
12: "Noon", 13: "Afternoon", 14: "Afternoon", 15: "Mid Afternoon", 16: "Late Afternoon",
17: "Evening Rush", 18: "Peak Evening Rush", 19: "Evening Rush",
20: "Late Evening", 21: "Night", 22: "Late Night",
}
WESTERN_STATIONS_ORDER = [
"Churchgate", "Marine Lines", "Charni Road", "Grant Road",
"Mumbai Central", "Mahalaxmi", "Lower Parel", "Dadar",
"Bandra", "Andheri", "Borivali", "Virar"
]
CENTRAL_STATIONS_ORDER = [
"CSMT", "Masjid", "Sandhurst Road", "Byculla",
"Dadar", "Kurla", "Ghatkopar", "Thane", "Kalyan"
]
HARBOUR_STATIONS_ORDER = [
"CSMT", "Masjid", "Dockyard Road", "Wadala Road",
"Kurla", "Vashi", "Nerul", "Panvel"
]
def get_risk_info(crowd_level: str) -> Dict:
return RISK_CONFIG.get(crowd_level, RISK_CONFIG["Low"])
def build_reasoning(
line: str, station: str, destination: str,
direction: str, hour: int, day_of_week: str,
crowd_level: str
) -> List[str]:
reasons = []
is_weekday = day_of_week not in ["Saturday", "Sunday"]
is_morning_peak = 7 <= hour <= 9
is_evening_peak = 17 <= hour <= 19
is_southbound = direction == "Southbound"
hour_label = HOUR_LABELS.get(hour, "")
# Time-based
if is_morning_peak:
reasons.append(f"⏰ {hour_label} ({hour}:00) β€” peak office hours create high demand")
elif is_evening_peak:
reasons.append(f"⏰ {hour_label} ({hour}:00) β€” peak return hours, trains are packed")
elif hour < 6:
reasons.append(f"⏰ Early morning ({hour}:00) β€” very few commuters at this hour")
elif hour > 21:
reasons.append(f"⏰ Late night ({hour}:00) β€” minimal traffic")
else:
reasons.append(f"⏰ {hour_label} ({hour}:00) β€” off-peak period")
# Day type
if is_weekday:
reasons.append(f"πŸ“… {day_of_week} is a working day β€” 20-30% more passengers than weekends")
else:
reasons.append(f"πŸ“… {day_of_week} is a weekend β€” lighter traffic overall")
# Directional logic
if is_morning_peak and is_southbound and is_weekday:
reasons.append("πŸš† Southbound during morning rush β€” commuters flooding into the city")
elif is_morning_peak and not is_southbound and is_weekday:
reasons.append("πŸš† Northbound during morning rush β€” outbound direction, relatively lighter")
elif is_evening_peak and not is_southbound and is_weekday:
reasons.append("πŸš† Northbound during evening rush β€” commuters heading home to suburbs")
elif is_evening_peak and is_southbound and is_weekday:
reasons.append("πŸš† Southbound during evening β€” reverse commute, lighter than northbound")
# Line-specific
if line == "Western":
reasons.append("πŸ›€οΈ Western Line β€” highest ridership line in Mumbai (approx. 4M+ daily)")
elif line == "Central":
reasons.append("πŸ›€οΈ Central Line β€” second busiest, serves eastern suburbs & Thane district")
elif line == "Harbour":
reasons.append("πŸ›€οΈ Harbour Line β€” connects Navi Mumbai, generally less crowded")
return reasons
def get_best_hours(
model, le_station, le_dest,
line: str, station: str, destination: str, direction: str, day: str,
predict_fn
) -> List[Dict]:
results = []
for h in range(5, 23):
pred = predict_fn(model, le_station, le_dest, line, station, destination, direction, h, day)
results.append({
"hour": h,
"label": f"{h:02d}:00",
"crowd_level": pred["crowd_level"],
"risk_score": RISK_CONFIG[pred["crowd_level"]]["score"],
"confidence": pred["confidence"]
})
return results
def get_travel_tip(crowd_level: str, direction: str, hour: int) -> str:
tips = {
"Low": [
"Perfect time to travel! You'll likely get a seat.",
"Great window! Trains are comfortable right now.",
"Off-peak bliss β€” smooth, uncrowded journey ahead.",
],
"Medium": [
"Manageable crowd β€” you may have to stand for a while.",
"Arrive 5 mins early to board comfortably.",
"It's busy but not terrible. Avoid the first bogie.",
],
"Extreme": [
"Packed trains! If flexible, shift by 30–60 minutes.",
"Consider the Ladies' Special or next train.",
"Carry water, maintain patience β€” it's Mumbai rush!",
]
}
import random
opts = tips.get(crowd_level, tips["Medium"])
return opts[hour % len(opts)]