Skip to main content

Download, filter, and aggregate NHTSA FARS fatal-crash data with zero non-stdlib dependencies.

Project description

fars-toolkit

Download, filter, and aggregate NHTSA FARS fatal-crash data with zero non-stdlib dependencies.

A small, focused Python library for indie data-journalism and research workflows. No pandas, no PyArrow, no Spark — just the standard library, the public NHTSA FARS CSV downloads, and a few dozen lines that handle the annoying parts (BOM bytes, varying folder layouts, the BODY_TYP join).

If you're doing serious modelling work, use pandas or polars. If you want to pull seven years of FARS, filter to crashes involving a specific vehicle class, and aggregate per-city or per-state, this is the lighter path.

Companion to the published research:

Install

pip install fars-toolkit

Requires Python ≥ 3.9. No dependencies outside the standard library.

Quick start

from fars_toolkit import (
    download_year, load_year, truck_cases, by_city, by_state
)

# 1. Pull the 2024 zip (~32 MB) into ./data/ and extract.
download_year(2024, into='data/')

# 2. Locate the inner CSVs. Folder layout varies year to year; this handles
#    the 2018-2024 vintages automatically.
accident, vehicle = load_year(2024, base='data/')

# 3. Find all crashes that involved a medium/heavy commercial truck.
#    By default, body types 60-69 (the standard NHTSA truck definition).
cases = truck_cases(vehicle)

# 4. Aggregate fatalities by (state, city) FIPS code.
per_city = by_city(accident, cases)
print(per_city[(17, 1670)])   # truck-involved fatalities in Chicago, IL, 2024

# 5. Or aggregate by state.
per_state = by_state(accident, cases)
print(per_state[6])           # truck-involved fatalities in California, 2024

What it handles

NHTSA's FARS CSVs have a few rough edges that bit me when I built the Vision Zero Report Card and inspired this package:

  • BOM bytes in 2021–2024 files. Reading naïvely with utf-8 fails on 2018 files; reading with latin-1 leaves a BOM visible as  on the first column header, which silently breaks the dict key lookup. open_fars_csv() strips it transparently.
  • Folder layout varies. 2018–2019 zips extract their CSVs directly into the target folder. 2020+ wrap them in an inner FARS{year}NationalCSV/ subfolder. load_year() tries both.
  • Multi-table join. A "truck-involved crash" is defined on the vehicle table (one row per vehicle, where BODY_TYP is in 60–69) but the fatality count lives on the accident table. truck_cases() + by_city() does that join cleanly without loading everything into memory.

Truck definition

By default, truck_cases() uses FARS BODY_TYP codes 60–69 — medium and heavy commercial trucks. This matches the truck-crash definition NHTSA and IIHS use in safety research; it excludes passenger pickups under 10,000 lb GVWR.

You can pass a custom set:

from fars_toolkit import truck_cases

# Only truck-tractors (semis):
semi_cases = truck_cases('vehicle.csv', body_types={68})

# Step vans and HAZMAT placards:
small_truck_cases = truck_cases('vehicle.csv', body_types={60, 61})

The package exposes BODY_TYP_LABELS if you want human-readable labels for each code.

CLI

The library ships a thin CLI for the common one-liners:

# Download a batch of years.
fars-toolkit download --year 2018 2019 2020 2021 2022 2023 2024 --into data/

# Top 20 cities by truck-involved fatalities in 2024.
fars-toolkit cities --year 2024 --base data/ --top 20

# Per-state truck-fatality totals for 2024.
fars-toolkit state-totals --year 2024 --base data/

API summary

Function What it does
download_year(year, into=...) Fetch and extract a FARS National CSV zip.
load_year(year, base=...) Locate the accident.csv + vehicle.csv paths inside an extracted folder.
truck_cases(vehicle, body_types=...) Return the set of (state, st_case) crash IDs whose vehicle is a truck.
by_city(accident, cases=...) Aggregate FATALS by (state, city) FIPS, optionally restricted to a case set.
by_state(accident, cases=...) Aggregate FATALS by state FIPS.
series_for_city(state, city, years, base=...) Build a year → fatalities series for one city across multiple years.
open_fars_csv(path) Encoding-tolerant csv.DictReader opener, BOM-stripped.

Caveats inherited from FARS

These are the caveats baked into the underlying NHTSA data; the package can't fix them, but you should know:

  • City boundaries. FARS uses federal FIPS city codes. Crashes on through-routes at city limits sometimes attribute to the surrounding county instead of the city, so urban truck-deaths are likely undercounted for cities with major interstate-through-routes.
  • 2024 is preliminary. The 2024 Annual Report File released April 2026 will be re-released as the Final File in 2027 and may revise counts slightly.
  • Small annual counts are noisy. For cities with single-digit annual truck fatalities, year-over-year percentage swings reflect statistical noise as much as policy outcomes.

License

MIT.

Related

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fars_toolkit-0.1.0.tar.gz (12.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fars_toolkit-0.1.0-py3-none-any.whl (11.5 kB view details)

Uploaded Python 3

File details

Details for the file fars_toolkit-0.1.0.tar.gz.

File metadata

  • Download URL: fars_toolkit-0.1.0.tar.gz
  • Upload date:
  • Size: 12.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for fars_toolkit-0.1.0.tar.gz
Algorithm Hash digest
SHA256 af87d42aba69687c492ebeb14141d90a3430f0b89b6f2238c957254104baed1e
MD5 406f48196628c14af40cca02fad9e513
BLAKE2b-256 b74090c1349a3a11314959ba1ebcd1713a246e1987760cd4325294b678a8d3c8

See more details on using hashes here.

File details

Details for the file fars_toolkit-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: fars_toolkit-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 11.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for fars_toolkit-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 649d2c299cca8e1ac7ee77b33028d901f5aff6298302e6406b4af9ab2825f0fb
MD5 af5f5050d1b5cb7b96a0dbea65b54018
BLAKE2b-256 1043c72dc4ebb7cb4c204308e5cbb03e9f7c89cd565c0ace08d2d57c2129974b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page