Find when and where delays are most likely, so operators can adjust service and improve reliability.
A simple path: problem → data → patterns → model → what to do with it.
Even small delays can break connections and reduce trust. The goal is to support operations with an early warning signal.
I want a simple, useful way to spot “higher risk” situations early.
Think of it as a “heads up” for dispatch and planning teams.
The goal is not “perfect prediction”. The goal is a model that helps make better decisions.
One cleaned dataset is used for both analysis and modeling, so the numbers always match.
Important rule: I keep one cleaned dataset so EDA and modeling are consistent.
Extract with SQL and export a CSV for analysis.
Fix types, check missing values, and review extreme delays.
Look at delays by hour, day, route/stop, and conditions.
Build useful columns (time bands, route context, weather flags).
Compare models using F1, plus Precision/Recall and ROC AUC.
Each row is one bus stop event with a scheduled time and an observed time. With millions of rows, I can spot patterns and train models with confidence.
| Column | Type | Meaning |
|---|---|---|
| stop_id | categorical | Stop identifier (where the bus event happened) |
| trip_id | categorical | Trip identifier (specific run of a bus line) |
| planned_time | datetime | Scheduled arrival/departure time at the stop |
| real_time | datetime | Observed arrival/departure time at the stop |
| delay_minutes | numeric | Difference between real and planned time (minutes) |
| collected_at | datetime | Timestamp when the observation was recorded |
| operator | categorical | Operator/company running the service (some missing values) |
| transport_type | categorical | Transport mode label (bus category in this dataset) |
| route_id | categorical | Internal route identifier |
| route_short_name | categorical | Public-facing line number/name |
For each stop event, the model predicts one of two outcomes: Delayed or On-time.
I use 1 minute as a clear and simple rule that matches how I talk about reliability.
I also report Precision, Recall, and ROC AUC to give extra context.
is_delayed (Delayed ≥ 1 minute).
Before modeling, I check missing values and I look at the delay distribution to understand what “normal” looks like.
| Check | What I saw | Why it matters |
|---|---|---|
| Missing values | Very small | I can compare routes/operators without big data gaps. |
| Typical delay size | P95 ≈ 5 min, P99 ≈ 9 min | Most delays are minor, so small operational fixes can help many trips. |
| Extreme delays | Rare but can be huge (chart capped at 75+) | Averages can be misleading; treat rare extremes as disruption cases. |
| Target rule | Delayed = ≥ 1 minute | Keeps EDA and modeling aligned and easy to explain. |
This chart shows the share of stop events that are delayed for each planned hour.
Think of this as a simple “when should I watch more closely?” signal.
Same metric as before: delayed share (Delayed = ≥ 1 minute). Dashed line = overall baseline.
I rank routes by delayed share (Delayed = ≥ 1 minute). I only keep routes with many events so the ranking is fair.
This creates a short “priority list” instead of trying to fix everything at once.
I rank stops by delayed share (Delayed = ≥ 1 minute). I only keep stops with many events so the ranking is fair.
This slide is meant to create a short, practical “investigation list”.
This is helpful for monitoring. But operators run different routes and areas, so I must compare carefully.
Earlier I looked at how often delays happen. Here I look at how many minutes the delay is (only for delayed events).
Correlation is a simple way to see which variables “travel together”. It helps spot overlap and obvious mistakes.
I predict Delayed vs On-time (Delayed ≥ 1 min) using only information known before the bus reaches the stop.
| Group | Columns | How I handle it |
|---|---|---|
| Numeric | planned_hour, planned_weekday, rain, route_volume, stop_volume |
LR: scale numbers (StandardScaler) Trees (RF/GB): use as-is |
| Binary | is_weekend, is_rainy, is_heavy_rain | use as-is |
| Small categories | operator (≈5), time_band (≈5) | One-hot (safe with new values) |
| Large IDs | stop_id (≈2494), route_id (≈589), route_short_name (≈568) |
LR baseline: not used RF: OrdinalEncoder (unknown = -1) |
I compare a simple baseline to stronger tree models, and I choose the one with the best balance between missed delays and false alarms.
The model gives a probability. I choose a threshold to decide when to flag Delayed vs On-time (Delayed ≥ 1 min).
These curves check if the model is truly useful, not just at one threshold. (Delayed = ≥ 1 minute.)
This chart ranks features by importance inside the Random Forest. Bigger bars mean the model used that feature more.
The model does not “fix” delays by itself. It helps teams focus on the trips that are more likely to run late.
The model is useful, but some delays are hard to predict without real-time information.
This concludes my presentation.