88
99### [ ▶ View Live Dashboard Demo] ( https://snaidu20.github.io/Crashlens/ )
1010
11- ![ CrashLens Dashboard Preview] ( dashboard-preview.png )
12-
1311---
1412
1513## Table of Contents
@@ -74,7 +72,7 @@ CrashLens shifts this to **proactive, condition-based risk assessment** by:
7472| ** Years** | 2020, 2021, 2022, 2023 |
7573| ** Total Crash Events** | 205,874 |
7674| ** Total Person Records** | 477,801 motor vehicle occupants |
77- | ** Tables Used** | ACCIDENT, VEHICLE, PERSON, DISTRACT, DRIMPAIR, CRASHRF, VSOE |
75+ | ** Tables Used** | ACCIDENT, VEHICLE, PERSON, DISTRACT, DRIMPAIR, CRASHRF, MANEUVER, DRIVERRF, VIOLATN |
7876| ** File Format** | CSV (Latin-1 encoding) |
7977| ** Download** | Each year is a separate ZIP archive containing CSV files |
8078
@@ -90,13 +88,13 @@ CrashLens shifts this to **proactive, condition-based risk assessment** by:
9088
9189> ** Class imbalance challenge:** Fatal crashes represent only 0.9% of records, making detection extremely difficult. This is addressed through SMOTE oversampling and class-weighted loss functions.
9290
93- ### Feature Groups (37 Total Features)
91+ ### Feature Groups (44 Total Features)
9492
9593| Group | Count | Features |
9694| -------| -------| ----------|
97- | ** Numeric** | 9 | ` AGE_CLEAN ` , ` TRAV_SP_CLEAN ` (travel speed MPH), ` SPEED_OVER_LIMIT ` , ` VEHICLE_AGE ` , ` VE_TOTAL ` (vehicles in crash), ` NUMOCCS ` (occupants), ` VSPD_LIM ` (posted speed limit), ` VNUM_LAN ` (lane count), ` NUM_CRASH_FACTORS ` |
98- | ** Categorical** | 13 | ` BODY_TYPE_CAT ` (vehicle type), ` LIGHT_CAT ` (lighting), ` WEATHER_CAT ` , ` COLLISION_TYPE ` , ` AGE_GROUP ` , ` SEX_CLEAN ` , ` RESTRAINT_CAT ` , ` AIRBAG_CAT ` , ` EJECTION_CAT ` , ` DEFORMATION_CAT ` , ` SURFACE_CAT ` , ` SPEED_LIMIT_CAT ` , ` TIME_PERIOD ` |
99- | ** Binary** | 10 | ` IS_WEEKEND ` , ` IS_DRIVER ` , ` MULTI_VEHICLE ` , ` ROLLOVER_FLAG ` , ` SPEED_RELATED ` , ` IN_WORK_ZONE ` , ` AT_JUNCTION ` , ` DISTRACTED ` , ` DRIVER_IMPAIRED ` , ` DRINKING_FLAG ` |
95+ | ** Numeric** | 11 | ` AGE_CLEAN ` , ` TRAV_SP_CLEAN ` (travel speed MPH), ` SPEED_OVER_LIMIT ` , ` VEHICLE_AGE ` , ` VE_TOTAL ` (vehicles in crash), ` NUMOCCS ` (occupants), ` VSPD_LIM ` (posted speed limit), ` VNUM_LAN ` (lane count), ` NUM_CRASH_FACTORS ` , ` NUM_DRIVER_RF ` (driver risk factor count), ` NUM_VIOLATIONS ` (violation count) |
96+ | ** Categorical** | 14 | ` BODY_TYPE_CAT ` (vehicle type), ` LIGHT_CAT ` (lighting), ` WEATHER_CAT ` , ` COLLISION_TYPE ` , ` AGE_GROUP ` , ` SEX_CLEAN ` , ` RESTRAINT_CAT ` , ` AIRBAG_CAT ` , ` EJECTION_CAT ` , ` DEFORMATION_CAT ` , ` SURFACE_CAT ` , ` SPEED_LIMIT_CAT ` , ` TIME_PERIOD ` , ` VTRAFCON_CAT ` (traffic control device) |
97+ | ** Binary** | 14 | ` IS_WEEKEND ` , ` IS_DRIVER ` , ` MULTI_VEHICLE ` , ` ROLLOVER_FLAG ` , ` SPEED_RELATED ` , ` IN_WORK_ZONE ` , ` AT_JUNCTION ` , ` DISTRACTED ` , ` DRIVER_IMPAIRED ` , ` DRINKING_FLAG ` , ` HAS_PRE_CRASH_MANEUVER ` (active maneuver), ` HAS_DRIVER_RF ` (risk factor flag), ` HAS_VIOLATION ` (violation flag), ` HIT_RUN_FLAG ` (driver fled scene) |
10098| ** Ordinal** | 5 | ` URBANICITY ` , ` REGION ` , ` DAY_WEEK ` , ` HOUR ` , ` MONTH ` |
10199
102100---
@@ -111,7 +109,7 @@ CrashLens/
111109│
112110├── pipeline/ # End-to-end data processing & model training
113111│ ├── 01_explore_data.py # Raw data exploration & statistics
114- │ ├── 02_merge_and_engineer.py # Table merging & feature engineering (37 features)
112+ │ ├── 02_merge_and_engineer.py # Table merging & feature engineering (44 features)
115113│ ├── 03_clean_and_encode.py # Missing values, encoding, cleaning
116114│ ├── 04_split_and_balance.py # Group-aware train/val/test split + SMOTE
117115│ ├── 05_validate_dataset.py # 33-check dataset quality validation
@@ -173,14 +171,16 @@ CrashLens/
173171
1741721 . ** Download** CRSS CSV archives from [ NHTSA] ( https://www.nhtsa.gov/file-downloads?p=nhtsa/downloads/CRSS/ ) for years 2020–2023
1751732 . Place each year's CSV folder into ` data/raw/crss_YYYY/CRSSYYYYCSV/ `
176- 3 . The script loads ** 7 core tables** across all 4 years:
174+ 3 . The script loads ** 9 tables** across all 4 years:
177175 - ` ACCIDENT ` — crash-level data (time, location, conditions)
178- - ` VEHICLE ` — vehicle-level data (type, speed, deformation)
176+ - ` VEHICLE ` — vehicle-level data (type, speed, deformation, hit-and-run, traffic control )
179177 - ` PERSON ` — person-level data (age, sex, injury severity, restraint)
180178 - ` DISTRACT ` — driver distraction factors
181179 - ` DRIMPAIR ` — driver impairment factors
182180 - ` CRASHRF ` — crash-related contributing factors
183- - ` VSOE ` — vehicle sequence of events (rollover detection)
181+ - ` MANEUVER ` — pre-crash driver maneuver (evasive action, turning, lane change)
182+ - ` DRIVERRF ` — driver-related risk factors (fatigue, inattention, aggressive driving)
183+ - ` VIOLATN ` — traffic violations at time of crash (speeding, signal violations, etc.)
1841844 . ** Outputs:** Console summary of record counts, target distribution, and missing value patterns
185185
186186```
@@ -195,12 +195,12 @@ Fatal injuries (K): 4,379 (0.9%)
195195
196196** Script:** ` pipeline/02_merge_and_engineer.py `
197197
198- This is the most complex step — it joins 7 tables and engineers 37 meaningful features from raw CRSS codes.
198+ This is the most complex step — it joins 9 tables and engineers 44 meaningful features from raw CRSS codes.
199199
200200** Merge Strategy:**
2012011 . ** Crash + Vehicle:** Join ` ACCIDENT ` and ` VEHICLE ` on ` (CASENUM, DATA_YEAR) ` via ` VEHNO `
2022022 . ** + Person:** Join with ` PERSON ` on ` (CASENUM, VEHNO, DATA_YEAR) ` via ` PER_NO `
203- 3 . ** + Supplementary tables:** Left-join ` DISTRACT ` , ` DRIMPAIR ` , ` CRASHRF ` , ` VSOE ` — aggregate to binary flags per vehicle/person
203+ 3 . ** + Supplementary tables:** Left-join ` DISTRACT ` , ` DRIMPAIR ` , ` CRASHRF ` , ` MANEUVER ` , ` DRIVERRF ` , ` VIOLATN ` — aggregate to binary flags per vehicle/person
204204
205205** Feature Engineering (key transformations):**
206206
@@ -217,7 +217,7 @@ This is the most complex step — it joins 7 tables and engineers 37 meaningful
217217| ` MAN_COLL ` | ` COLLISION_TYPE ` | 10+ codes → 7 categories (Rear_End, Angle, Head_On, Sideswipe, etc.) |
218218| ` DEFORMED ` | ` DEFORMATION_CAT ` | 7 codes → 5 categories (None, Minor, Functional, Disabling, Unknown) |
219219| Multiple tables | ` DISTRACTED ` , ` DRIVER_IMPAIRED ` , ` DRINKING_FLAG ` | Binary flags from supplementary tables |
220- | ` VSOE ` | ` ROLLOVER_FLAG ` | Binary: any rollover event in sequence |
220+ | ` VEHICLE ` | ` ROLLOVER_FLAG ` | Binary: derived from ROLLOVER field in vehicle table (VSOE not used) |
221221
222222** Output:** ` data/processed/crashlens_merged.parquet ` — 477,801 rows × 50+ columns
223223
@@ -227,7 +227,7 @@ This is the most complex step — it joins 7 tables and engineers 37 meaningful
227227
228228** Script:** ` pipeline/03_clean_and_encode.py `
229229
230- 1 . ** Select final 37 model features** from the merged dataset
230+ 1 . ** Select final 44 model features** from the merged dataset
2312312 . ** Handle CRSS coded unknowns:** Values like 98, 99, 998, 999 → treated as missing
2322323 . ** Missing value strategy:**
233233 - Numeric: median imputation
@@ -292,7 +292,7 @@ Used in loss functions for all models to further address imbalance.
292292Runs ** 33 automated quality checks** before model training:
293293
294294- No NaN/Inf values in any split
295- - Feature count matches config (37 features)
295+ - Feature count matches config (44 features)
296296- Class counts match between config and actual data
297297- No group leakage (no ` CASENUM ` overlap across splits)
298298- Value ranges are reasonable (age 0–120, speed 0–150, etc.)
@@ -362,11 +362,11 @@ Implements the **Feature Tokenizer + Transformer** (FT-Transformer) architecture
362362#### Architecture
363363
364364```
365- Input (37 features)
366- ├── Numeric features (24 ) → Linear projection → per-feature tokens (32-dim each)
367- └── Categorical features (13 ) → Learned embeddings → per-feature tokens (32-dim each)
365+ Input (44 features)
366+ ├── Continuous features (30 ) → Linear projection → per-feature tokens (32-dim each)
367+ └── Categorical features (14 ) → Learned embeddings → per-feature tokens (32-dim each)
368368 ↓
369- [CLS] token prepended → 38 tokens total
369+ [CLS] token prepended → 45 tokens total
370370 ↓
371371 Transformer Encoder (2 layers, 4 heads, d_ff=64, dropout=0.2)
372372 ↓
@@ -465,39 +465,39 @@ Consolidates all results into a single JSON file for the interactive dashboard:
465465
466466| Model | Accuracy | Balanced Accuracy | F1 Macro | Fatal (K) Sensitivity | Fatal (K) F1 |
467467| -------| ----------| -------------------| ----------| ----------------------| -------------|
468- | Random Forest | 71.7 % | 42 .5% | 41.9 % | 37.3 % | 34.3 % |
469- | XGBoost | 71.0 % | 44.3 % | 43.5 % | 37.0 % | 33.9 % |
470- | ** LightGBM** | ** 70.9 %** | ** 44.9 %** | ** 43 .0%** | ** 42.6 %** | ** 32.7 %** |
471- | FT-Transformer | 38.7 % | 44.1 % | 30.7 % | ** 61.1 %** | 25.1 % |
468+ | Random Forest | 72.0 % | 44 .5% | 43.0 % | 48.5 % | 40.5 % |
469+ | XGBoost | 71.4 % | 46.5 % | 45.3 % | 46.3 % | 40.7 % |
470+ | ** LightGBM** | ** 71.2 %** | ** 47.6 %** | ** 45 .0%** | ** 54.3 %** | ** 40.8 %** |
471+ | FT-Transformer | 35.5 % | 44.2 % | 31.2 % | ** 57.3 %** | 30.8 % |
472472
473473### Per-Class F1 Scores (Test Set — LightGBM)
474474
475475| Class | Precision | Recall | F1 Score |
476476| -------| -----------| --------| ----------|
477- | O — No Injury | 0.862 | 0.879 | 0.864 |
478- | C — Possible | 0.267 | 0.265 | 0.301 |
479- | B — Non-Incapacitating | 0.319 | 0.324 | 0.331 |
480- | A — Incapacitating | 0.310 | 0.353 | 0.328 |
481- | K — Fatal | 0.262 | 0.426 | 0.327 |
477+ | O — No Injury | 0.851 | 0.879 | 0.865 |
478+ | C — Possible | 0.350 | 0.270 | 0.305 |
479+ | B — Non-Incapacitating | 0.338 | 0.327 | 0.332 |
480+ | A — Incapacitating | 0.322 | 0.360 | 0.340 |
481+ | K — Fatal | 0.327 | 0.543 | 0.408 |
482482
483483### Confusion Matrix (LightGBM — Test Set)
484484
485485```
486486 Predicted: O C B A K
487- Actual O 58,886 4,419 2,451 1,138 154
488- Actual C 6,950 3,596 1,812 1,030 176
489- Actual B 2,563 1,600 2,792 1,418 234
490- Actual A 845 690 1,140 1,717 476
491- Actual K 66 43 95 302 376
487+ Actual O 58,944 4,411 2,503 1,052 138
488+ Actual C 6,931 3,668 1,803 997 165
489+ Actual B 2,506 1,657 2,816 1,405 223
490+ Actual A 817 694 1,145 1,753 459
491+ Actual K 51 39 76 237 479
492492```
493493
494494---
495495
496496## Key Findings
497497
498- 1 . ** LightGBM achieves the best balance** of overall accuracy (70.9 %) and fatal crash detection (42.6 % sensitivity) — it's the recommended model for general deployment.
498+ 1 . ** LightGBM achieves the best balance** of overall accuracy (71.2 %) and fatal crash detection (54.3 % sensitivity) — it's the recommended model for general deployment.
499499
500- 2 . ** FT-Transformer detects 61.1 % of fatal crashes** — 47% more than LightGBM — by trading overall accuracy. This suggests value in ensemble approaches for safety-critical applications where missing a fatal crash has high cost.
500+ 2 . ** FT-Transformer detects 57.3 % of fatal crashes** — evaluated from a partially-trained checkpoint (CPU constraint limited training to 6 epochs). It trades F1-macro for fatal sensitivity, suggesting value for safety-critical applications where missing a fatal crash has high cost.
501501
5025023 . ** Top risk factors identified by SHAP:**
503503 - ** Ejection** from vehicle → >20× fatality risk
0 commit comments