Skip to content

Commit 0a7f96c

Browse files
committed
Expand to 9 tables + 44 features: add MANEUVER, DRIVERRF, VIOLATN + HIT_RUN/VTRAFCON
Changes: - Pipeline Step 2: load maneuver, driverrf, violatn tables; aggregate to binary/count flags; add HIT_RUN_FLAG and VTRAFCON_CAT from vehicle table (were loaded but unused) - Pipeline Step 3: register 7 new features in clean/encode step - All splits and processed data regenerated with 44-feature schema - Retrained RF, XGBoost, LightGBM — all models improved on F1-macro and fatal recall - SHAP recomputed on updated LightGBM model - Dashboard JSON updated with new results - README corrected: 9 tables, 44 features, updated performance table and confusion matrix - Added 07b_eval_transformer.py for checkpoint eval without full retraining New model results (test set): Random Forest: F1=0.430 Fatal Recall=0.485 (was 0.419 / 0.373) XGBoost: F1=0.453 Fatal Recall=0.463 (was 0.435 / 0.370) LightGBM: F1=0.450 Fatal Recall=0.543 (was 0.430 / 0.426) FT-Transformer: F1=0.312 Fatal Recall=0.573 (partial checkpoint, CPU constrained)
1 parent daedcf5 commit 0a7f96c

15 files changed

Lines changed: 1087 additions & 869 deletions

CrashLens/README.md

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
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

174172
1. **Download** CRSS CSV archives from [NHTSA](https://www.nhtsa.gov/file-downloads?p=nhtsa/downloads/CRSS/) for years 2020–2023
175173
2. 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.)
184184
4. **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:**
201201
1. **Crash + Vehicle:** Join `ACCIDENT` and `VEHICLE` on `(CASENUM, DATA_YEAR)` via `VEHNO`
202202
2. **+ 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
231231
2. **Handle CRSS coded unknowns:** Values like 98, 99, 998, 999 → treated as missing
232232
3. **Missing value strategy:**
233233
- Numeric: median imputation
@@ -292,7 +292,7 @@ Used in loss functions for all models to further address imbalance.
292292
Runs **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

502502
3. **Top risk factors identified by SHAP:**
503503
- **Ejection** from vehicle → >20× fatality risk

0 commit comments

Comments
 (0)