Skip to main content

crimepy

Version PyPI Latest Release GitHub Latest Release
Status Build Status Code Coverage Development Status Project Stability
Documentation Hosted By
Tools Documentation Linter Type Checker Dependency Manager Pre-commit CI Editor Settings Repository Template Dependency Maintainer
Compatibility Compatible Python Versions Linux MacOS Windows
Stats PyPI Download Rate (per month) GitHub Stars GitHub Contributors GitHub Issues GitHub Forks

What is crimepy?

crimepy downloads, combines, munges, analyzes, and plots crime data. It starts with the FBI's National Incident-Based Reporting System (NIBRS): the yearly master files of every incident that participating law enforcement agencies reported, from 1991 to the latest year, published by the FBI's Crime Data Explorer. crimepy turns those fixed-width files into flat tables that work in pandas, and it is built on amos: every table is an amos.Dataset, every analysis is an amos technique, and a whole study (from loading the data to modeling and figures) can be described in a settings file.

Why use crimepy?

  • Any year, in one line. crimepy.nibrs.load('victims', '2015-2023') downloads the master files that are missing, parses them, and returns one table, with "data_year" saying which year each row came from.
  • Ready for amos. Tables come as amos datasets, which hold the data (a pandas data frame), its label and groups for modeling, and the tables, figures, and models that analyses add to them, so any amos model, validator, or plot works on them directly.
  • Flat tables with labels. Every segment of the master files becomes a table with one column per field. Codes become labeled categories ("20" becomes "Residence/Home"), dates become dates, ages become numbers, and missing values are missing (pd.NA), not blanks or zeros.
  • Fast and frugal. Each year is parsed once (a recent year, over 6 GB of text, takes about five minutes) and saved as compressed parquet files. After that, loading a table of a whole year takes seconds, and loading a few states or columns takes less.
  • Joined for analysis. crimepy.nibrs.tables joins an incident's segments into tables of incidents, victims, offenses, offenders, or arrestees, each with its incident's and agency's details: whether the incident was cleared, how many days until an arrest, the victim's relationship to the offender, the agency's population, and more.
  • Every year's quirks handled. The master files changed over three decades: batch headers split into three records before 2013, fields added in 2013, records padded to 132 characters or trimmed, and some years compressed with Deflate64, which Python's zipfile cannot read. crimepy reads them all and gives every year the same columns.
  • Analysis and figures included. Counts, trends, crime rates that use only agencies that reported all year, clearance rates, cross-tabulations, and reporting coverage, and figures of trends, the most common values, the hours and days of incidents, and age pyramids.
  • Reproducible studies. Every analysis and figure is an amos technique, so a study can load NIBRS data, reshape it, model it, and draw it from a plain settings file that doubles as a description of the methods.

Getting started

Requirements

crimepy requires Python 3.11 or later and runs on Linux, macOS, and Windows. Recent master files are about 600 MB to download, and their converted tables are about 500 MB on disk. Downloads and tables are saved in a "crimepy_data" folder in your home folder, unless you set the CRIMEPY_DATA environment variable or crimepy.options.DATA_FOLDER (or pass folder to any function).

Installation

To install crimepy, use pip:

pip install crimepy

To also install every optional package that amos can use for analysis (such as statsmodels and the boosting models):

pip install crimepy[analysis]

Usage

Load NIBRS data

import crimepy

victims = crimepy.nibrs.load('victims', years = '2021-2023', states = 'DE')
victims.data[['data_year', 'incident_date', 'offense_1', 'victim_age', 'victim_sex']].head()

load returns an amos.Dataset, whose data is the table (a pandas data frame). Pass label (and groups) to make it ready for modeling: crimepy.nibrs.load('victims', 2023, label = 'victim_age'). The first call downloads and converts each year, which takes a few minutes for a recent year. The tables of the master files are:

Table One row for each
agencies agency: location, population, type, and the months it reported
administrative incident: date, hour, numbers of segments, and exceptional clearance
offenses offense of an incident: offense, location, weapons, and bias motivations
properties property loss of an incident: type of loss, description, value, and drugs
victims victim: offenses, age, sex, race, injuries, and relationships to offenders
offenders offender: age, sex, race, and ethnicity
arrestees arrestee of an incident: date and type of arrest, offense, and person
group_b_arrests arrest for a Group "B" offense (such as disorderly conduct or DUI)
window_clearances, window_properties, window_arrestees partial report of an incident that began before its agency reported to NIBRS

Pass columns to load only some columns, and decode = False to keep the FBI's codes instead of their labels. crimepy.nibrs.load_frame returns the table as a plain data frame. crimepy.nibrs.read reads tables straight from a master file, without saving anything, which suits a quick look:

datasets = crimepy.nibrs.read('nibrs-2023.zip', limit = 100_000)
datasets['offenses'].data.head()

Combine the segments of incidents

incidents = crimepy.nibrs.tables.build('incidents', '2021-2023', states = 'DE')
incidents.data[['incident_date', 'offense_count', 'firearm', 'arrested', 'days_to_arrest', 'cleared']].head()

build makes a dataset with one row for each of the incidents, victims, offenses, offenders, or arrestees, with the details of its incident and agency. crimepy.combine.stack and crimepy.combine.merge stack and join any datasets (or data frames) while keeping their categories.

Analyze

from crimepy import analyze

agencies = crimepy.nibrs.load('agencies', '2021-2023', states = 'DE')
analyze.crime_rates(incidents, agencies, by = ['data_year', 'state'])
analyze.clearance_rates(incidents, by = ['data_year', 'agency_population_group'])
analyze.trend(incidents, date = 'incident_date', freq = 'MS')
analyze.coverage(agencies)

victims = crimepy.nibrs.tables.build('victims', 2023, states = 'DE')
analyze.crosstab(victims, 'victim_sex', 'relationship', normalize = 'index')

Each function applies an amos technique (see crimepy.techniques) and returns its table, which a dataset also keeps in its tables (such as incidents.tables['clearance_rates']). count makes a new dataset of counts, ready to model. crime_rates counts only agencies that reported in every month of the year, both for the crimes and for the population, so that agencies that did not report do not lower the rates. Without a table of agencies, it loads the agencies of the data's years and states.

Plot

offenses = crimepy.nibrs.tables.build('offenses', '2021-2023', states = 'DE')
figure = crimepy.plot.trend(offenses, by = 'offense_category', top = 5, freq = 'QS')
figure.savefig('trend.png')
crimepy.plot.top_values(offenses, 'location')
crimepy.plot.time_heatmap(incidents)
crimepy.plot.age_pyramid(victims, person = 'victim')

Each function returns the figure, and a dataset also keeps it in its figures (such as offenses.figures['trend_plot']).

Figures have amos's style for scientific journals, with colors that people with color blindness can tell apart.

Describe a study in a settings file

Every crimepy technique is an amos technique, so a study can be a settings file. This one loads three years of Delaware's incidents, counts them by size of agency, month, and day of the week, and compares two models of the counts (poisson needs pip install crimepy[analysis]):

[general]
seed = 43
label = count

[crime_project]
crime_workers = wrangler, analyst, critic

[wrangler]
techniques = load_nibrs, count_crimes

[load_nibrs_parameters]
table = incidents
years = 2021-2023
states = DE

[count_crimes_parameters]
by = agency_population_group, incident_month, incident_weekday

[analyst]
design = experiment
criterion = rmse
steps = split, encode, model
split_techniques = train_test
encode_techniques = one_hot
model_techniques = poisson, random_forest

[critic]
techniques = scorecard
project = crimepy.Project.create('crime.ini')
project.scorecard.table

From the command line

crimepy nibrs years
crimepy nibrs download 2021-2023
crimepy nibrs convert 2021-2023
crimepy nibrs export victims 2023 --states DE MD --output victims.csv
crimepy project crime.ini --export

See the tutorial, the advanced user guide (which explains the master files and every choice crimepy makes in reading them), and the recipes.

Contributing

Contributors are always welcome. Feel free to grab an issue to work on or make a suggested improvement. If you wish to contribute, please read the Contribution Guide and Code of Conduct.

Similar Projects

Acknowledgments

The data come from the FBI's Uniform Crime Reporting Program and the thousands of law enforcement agencies that report to it. The positions of the fields follow the FBI's "NIBRS Flatfile Yearly Master Record Descriptions", which the Crime Data Explorer distributes with the master files.

Citation

If you use crimepy in your research, please cite it. GitHub's "Cite this repository" button reads the same information from CITATION.cff.

@software{yung_crimepy,
  author  = {Yung, Corey Rayburn},
  title   = {crimepy: Accessible tools for downloading, combining, munging, analyzing, and plotting crime data},
  version = {0.1.0},
  year    = {2026},
  url     = {https://github.com/WithPrecedent/crimepy},
  license = {Apache-2.0}
}

License

Use of this repository is authorized under the Apache Software License 2.0.

Metadata

Release files for crimepy 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for crimepy 0.1.0
File Size Uploaded Provenance Actions
crimepy-0.1.0.tar.gz 409.1 kB Without provenance Details for crimepy-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for crimepy 0.1.0
File Interpreter ABI Platform Actions
crimepy-0.1.0-py3-none-any.whl Python 3 none any Details for crimepy-0.1.0-py3-none-any.whl

Total release size: 476.6 kB

Release files / crimepy-0.1.0.tar.gz

Download URL crimepy-0.1.0.tar.gz
Size 409.1 kB
Tags Source
SHA-256 checksum
How to use checksums
422eb39278ef2d1aa2584d83a0b7d86b7ec445f4dd431c9d02aba67c8b438504
BLAKE2b-256 checksum
How to use checksums
e464846836e6a41bf8569d82891b6af11a89d265ac2e6a0b47f0fd101a62c388
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / crimepy-0.1.0-py3-none-any.whl

Download URL crimepy-0.1.0-py3-none-any.whl
Size 67.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2c2beeec89ea0b40ba0407d8f7d743a9b254cca45e235c797f50d78d5670c353
BLAKE2b-256 checksum
How to use checksums
28fa9f70cbe7a19db5e9fe5bb9237d9c2b0ff0c8560390c23dccd6da13c71b26
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for crimepy 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page