Exploratory data analysis of ~1 million LAPD crime records (2020–2024), delivered as a reusable Python pipeline + interactive Plotly dashboard.
This project analyses five years of reported crime in Los Angeles to answer three questions:
- When does crime happen? (year / month / weekday / hour patterns)
- Where does it concentrate? (LAPD areas, streets, geographic hot spots)
- Against whom, and how? (victim demographics, weapons, premises)
It is deliberately structured like a real analytics deliverable rather than a single-notebook script: all logic lives in a tested src/ package (loader → cleaner → analyzer → visualizer → insights), and the notebook only orchestrates and narrates. The executive report in reports/ is generated automatically from the data — no hard-coded numbers.
┌──────────────┐
raw CSV ─────▶ │ data_loader │ schema-aware load, overview, dtypes
└──────┬───────┘
▼
┌──────────────┐
│ cleaner │ 8-step pipeline: dedupe, dates, HHMM time,
└──────┬───────┘ placeholder ages, imputation, features
▼
┌──────────────┴──────────────┐
▼ ▼
┌──────────────┐ ┌──────────────┐
│ analyzer │ ───────────▶ │ visualizer │ 24 themed Plotly/Matplotlib
└──────┬───────┘ tidy frames └──────────────┘ chart builders
▼
┌──────────────┐
│ insights │ live metrics → key findings → executive report (md)
└──────────────┘
Computation (analyzer) and presentation (visualizer) are strictly separated — every chart builder receives a tidy DataFrame and returns a figure.
| Source | Crime Data from 2020 to 2024 — LA Open Data Portal |
| Size | ~1M rows × 28 columns (~250 MB CSV) |
| Grain | One row per reported crime incident |
| Key fields | date/time occurred, LAPD area, crime code & description, victim age/sex/descent, weapon, premise, status, lat/lon |
| Status | Frozen — LAPD migrated to NIBRS reporting in 2024, so this dataset is stable historical reference data |
The raw CSV is not committed to the repo (see
.gitignore). Download it from the portal and place it atdata/raw/crime_data_la.csv.
- Transparent 8-step cleaning pipeline with a logged audit trail (duplicates removed, placeholder ages nulled, HHMM times validated, Null-Island coordinates masked, structurally-missing values encoded explicitly)
- Feature engineering: year, month, weekday, hour, time-of-day buckets, weekend flag, 9-category crime taxonomy (keyword rules over ~140 raw offense codes), reporting-delay days
- 20+ analyses: temporal trends at four granularities, region comparison, victim demographics, weapon & premise rankings, correlation matrix, IQR outlier detection at record and city level
- 24 professional visualizations: bar, pie/donut, line, area, histogram, box, scatter, heatmaps, treemap, sunburst, geographic scatter map — all consistently themed
- Interactive dashboard with dropdown filters (crime category, LAPD area) that work even in static HTML exports
- Auto-generated executive report (
reports/crime_analysis_report.md) recomputed live from the data - Data-artifact awareness: noon default times, first-of-month default dates, and the 2024 NIBRS-migration cutoff are identified and handled rather than misread as trends
| Layer | Tools |
|---|---|
| Language | Python 3.10+ |
| Data wrangling | Pandas, NumPy |
| Visualization | Plotly (interactive), Matplotlib (static) |
| Environment | Jupyter Notebook / VS Code |
| Storage | CSV in, Parquet out (pyarrow) |
Crime-Pattern-Analysis-Dashboard/
│
├── data/
│ ├── raw/ # place crime_data_la.csv here (git-ignored)
│ └── processed/ # cleaned parquet written by the pipeline
│
├── notebooks/
│ └── Crime_Pattern_Analysis.ipynb # main analysis (orchestration + narrative)
│
├── src/
│ ├── utils.py # paths, logging, LAPD code mappings, category rules
│ ├── data_loader.py # schema-aware loading + dataset overviews
│ ├── cleaner.py # 8-step cleaning & feature-engineering pipeline
│ ├── analyzer.py # 20 aggregation / statistics functions
│ ├── visualizer.py # 24 themed chart builders
│ └── insights.py # live metrics, findings, executive report
│
├── reports/ # auto-generated executive report
├── images/ # exported chart PNGs
├── README.md
├── requirements.txt
├── LICENSE
└── .gitignore
# 1. Clone
git clone https://github.com/deepthishivani/Crime-Pattern-Analysis-Dashboard.git
cd Crime-Pattern-Analysis-Dashboard
# 2. Virtual environment
python -m venv venv
venv\Scripts\activate # Windows
# source venv/bin/activate # macOS / Linux
# 3. Dependencies
pip install -r requirements.txt
# 4. Dataset
# Download "Crime Data from 2020 to 2024" from
# https://data.lacity.org (dataset id 2nrs-mtv8) → Export → CSV
# Save it as: data/raw/crime_data_la.csv
# 5. Run
jupyter notebook notebooks/Crime_Pattern_Analysis.ipynb
# (or open the folder in VS Code and run the notebook there)Run all cells top-to-bottom. The pipeline logs every cleaning step, writes the processed dataset to data/processed/, exports charts to images/, and generates reports/crime_analysis_report.md.
| Category | Charts |
|---|---|
| Temporal | yearly bars with YoY %, monthly time series + rolling average, seasonality bars, weekday bars, hourly area chart, weekday×hour heatmap |
| Composition | category donut, top-15 crimes bar, treemap (category→offense), sunburst (category→time-of-day) |
| Regional | area ranking colored by dominant category, area×year heatmap, top street addresses, interactive geographic scatter map |
| Demographics | age histogram, age-by-category box plots, sex donut, descent bars |
| Statistical | annotated correlation heatmap, daily-volume outlier scatter with IQR bounds, age-vs-reporting-delay scatter |
| Dashboard | 2×2 overview + dropdown-filtered interactive monthly trend |
![]() |
![]() |
![]() |
![]() |
- Property crime (theft/burglary + vehicle crime) dominates the composition; vehicle theft is the single most reported offense in the city.
- Crime intensity peaks Friday–Saturday evenings, with weekend late-nights staying hot while weekday nights cool off — a direct patrol-scheduling insight.
- The exact-noon spike in hourly data and first-of-month spikes in daily data are LAPD default-value recording artifacts, not real patterns — identified and flagged rather than misreported.
- The steep 2024 decline is a system-migration artifact (NIBRS transition), demonstrated in the analysis rather than misread as a crime drop.
- Crime is hyper-concentrated: a handful of LAPD areas and even individual street blocks account for a disproportionate share of all incidents, and the concentration is stable across all five years.
(The full, always-current list is generated in reports/crime_analysis_report.md.)
- Census joins → per-capita crime rates by area and demographic group
- Extend pipeline to LAPD's post-2024 NIBRS offense/victim datasets
- Time-series forecasting (SARIMA / Prophet) per crime category
- Streamlit/Dash deployment of the dashboard outside Jupyter
- DBSCAN geospatial clustering to formalize hot-spot detection
- Unit-test suite (pytest) over the cleaning pipeline
Released under the MIT License.
Deepthi Shivani — B.Tech CSE, SRM Institute of Science and Technology GitHub: @deepthishivani



