Skip to main content

NRCD performance standardization formulas (cross country, track, road)

Project description

nrcd

Python library for National Running Club Database (NRCD) performance standardization (cross country, track, road race). Implements the formulas documented in the NRCD resource paper.

GitHub Python 3.10+ PyPI License: MIT CI

Use this to standardize your own race results — no NRCD dataset download required.

Quick start

Times can be seconds or clock strings ("22:15", "4:12.00", "10.52"). XC distances accept m/km/mi or labels like "5k". Invalid time, distance, or unit strings raise ValueError with a short hint (they do not return NaN silently).

Cross country — pass a target distance when you want a Riegel conversion (e.g. 8000m). Without it, the standardized time stays at the race distance.

Cross country — 5K in 22:15, target distance 8000m

from nrcd import format_time, standardize_xc

std = standardize_xc(
    "22:15",
    gender="M",
    reported_distance="5k",
    target_distance_m=8000,  # 8000m
    # target_distance="8k",
    # target_distance=8, target_distance_unit="km",
    # target_distance=4.97, target_distance_unit="mi",  # ~8000m
)
print(format_time(std))
# → 36:31.94

Cross country — 8 km with weather, grade, altitude, target distance 8000m

from nrcd import format_time, standardize_xc

std = standardize_xc(
    "27:30",
    gender="M",
    reported_distance=8,
    distance_unit="km",
    actual_distance=8.01,
    temperature=72,          # °F (default)
    dew_point=65,
    elevation_gain=2.5,      # % grade (default)
    elevation_loss=2.5,
    meet_elevation=5200,     # feet (default)
    target_distance_m=8000,  # 8000m
)
print(format_time(std))
# → 26:42.19

Outdoor track — 100m with wind

from nrcd import standardize_outdoor_track

std = standardize_outdoor_track(
    "13.52",
    gender="F",
    event_name="100m",
    wind_mps=2.0,
)
print(f"{std:.3f} s")
# → 13.630 s

Indoor track — 200m on a banked 200m oval

from nrcd import standardize_indoor_track

std = standardize_indoor_track(
    "21.80",
    gender="M",
    event_name="200m",
    lap_length_m=200,
    banked=True,
)
print(f"{std:.3f} s")
# → 22.588 s

Road — half marathon with weather and grade

from nrcd import format_time, standardize_road

std = standardize_road(
    "1:25:30",
    gender="F",
    event_name="Half Marathon",
    temperature=55,
    dew_point=48,
    elevation_gain=1.2,
    elevation_loss=1.2,
)
print(format_time(std))
# → 1:25:40.54 (same event distance; no Riegel target conversion)

Pipelines

Sport Function What differs
Cross country standardize_xc Weather, grade, altitude; optional Riegel to a target distance (e.g. 8000m)
Road standardize_road Same weather / grade / altitude as XC; distance from event_name; no Riegel target
Outdoor track standardize_outdoor_track Sprint wind, weather, grade, altitude
Indoor track standardize_indoor_track Lap/bank venue factors; no wind

standardize_result remains available when you need a custom sport_name string.

Unit switches (optional kwargs on all pipelines):

Field Default Alternative
temperature, dew_point °F temp_unit="C"
meet_elevation feet venue_elevation_unit="m"
elevation_gain, elevation_loss % grade grade_input="feet" or "m"

More examples

Runnable scripts in examples/:

Script
XC xc_examples.py, compare_improvement.py, standardize_one_result.py
Track track_outdoor_examples.py, track_indoor_examples.py, track_compare_meets.py
Both race_context_example.py, load_dataset_example.py

load_dataset_example.py exits with code 1 if Zenodo CSVs are not in data/ — that is expected without the optional dataset.

pip install nrcd
python examples/xc_examples.py
python examples/track_outdoor_examples.py

Install

Requires Python 3.10+.

pip install nrcd              # after first PyPI release
pip install "nrcd[apis]"      # optional: weather / elevation APIs
pip install "nrcd[data]"      # optional: Zenodo CSV helpers (pandas)

Until the package is on PyPI, install from source:

git clone https://github.com/National-Running-Club-Database/nrcd
cd nrcd
pip install -e .

From source (development):

git clone https://github.com/National-Running-Club-Database/nrcd
cd nrcd
pip install -e ".[dev]"
pip install -e ".[dev,apis]"

API keys (optional — nrcd.enrich only)

Standardization does not need API keys. Use enrichment only when backfilling weather or meet altitude from city/state.

  1. pip install "nrcd[apis]"
  2. OpenWeatherAPI keys → set NRCD_OPENWEATHER_API_KEY
  3. For weather at a race date/time, also TimeZoneDBNRCD_TIMEZONE_API_KEY
  4. Meet altitude uses free USGS EPQS (no key) after OpenWeather geocodes the city
export NRCD_OPENWEATHER_API_KEY="your_key"
export NRCD_TIMEZONE_API_KEY="your_key"   # weather only
export NRCD_GEOCODE_COUNTRY_SUFFIX=US     # optional; ISO country for geocoding

Live tests (optional): copy local_api_keys.env.examplelocal_api_keys.env (gitignored), add your OpenWeather key, then pytest -m live_api -v. AQI history starts 2020-11-27; default test date is 2024-10-12.

Full walkthrough: API keys guide. In Python: from nrcd.enrich import API_GUIDE; print(API_GUIDE).

Historical OpenWeather timemachine weather may require a paid OpenWeather plan; geocoding + USGS altitude often work on the free tier.

Geographic coverage (nrcd.enrich)

Method Example Weather Altitude (USGS)
US city + state city="Notre Dame", state="IN" ✅ (US)
City + country city="London", country="GB" ⚠️ set meet_elevation non-US
Free-form query geocode_query="Paris,FR" ⚠️ same
Config / env default country EnrichConfig(geocode_country_suffix="CA") or NRCD_GEOCODE_COUNTRY_SUFFIX=CA ⚠️ same
Lat/lon latitude=51.5, longitude=-0.12 ✅ global ⚠️ US-focused EPQS
import datetime as dt
from nrcd.enrich import EnrichConfig, enrich_race_context
from nrcd.standardize import RaceContext

# International weather — city + country (no US state required)
ctx = RaceContext(
    time_str="15:30",
    gender="M",
    sport_name="Cross Country",
    reported_distance="10k",
    city="London",
    country="GB",
    event_date=dt.date(2024, 10, 12),
    event_time=dt.time(11, 0),
)
enrich_race_context(ctx, fetch_altitude=False)  # skip USGS outside US

# Or free-form geocode query
ctx.geocode_query = "Paris,FR"

Standardization has no geographic limit — only optional enrichment does.

Do you need the NRCD dataset?

Use case Zenodo CSVs needed?
Standardize your own results No
examples/ scripts No
nrcd.enrich API backfill No
examples/load_dataset_example.py only Yes (optional)

Optional public export: Zenodo dataset (see data/README.md).

API

Full parameter tables: from nrcd import PARAMETERS_DOC or help(nrcd.standardize).

Entry points

Function Use for
standardize_xc Cross country — optional target distance (target_distance_m, target_distance + unit, or "8k")
standardize_road Road / marathon — event_name; weather, grade, altitude
standardize_outdoor_track Outdoor track — event_name; wind on sprints
standardize_indoor_track Indoor track — event_name; lap length / banking
standardize_result Low-level — any sport_name (advanced)
standardize_seconds Dispatch from a RaceContext / XCRaceContext row
enrich_race_context Fill missing weather/altitude on a context (pip install "nrcd[apis]")

nrcd.standardize — pipelines & context

Name Description
RaceContext Dataclass for one result (XC or track); time_str or time_sec
XCRaceContext XC-focused RaceContext subclass
StandardizeConfig Paper coefficients (Riegel exponents, heat k, grade bases, …)
PARAMETERS_DOC Full required/optional parameter reference (text)
PARAMETER_SPECS Same metadata as structured ParameterSpec tuples
parameter_specs() Return PARAMETER_SPECS
`required_for("xc" "road"

nrcd.standardize — time, distance, units

Name Description
parse_time "22:15", "1:10:13", or seconds → float seconds
format_time Seconds → clock string
parse_distance "5k", 8, "8000m" + unit → meters
distance_to_meters Numeric distance with distance_unit (m / km / mi)
c_to_f, f_to_c Temperature conversion
feet_to_meters, meters_to_feet Length conversion
temperature_to_fahrenheit Value + temp_unit (F / C) → °F
venue_elevation_to_feet Meet altitude + venue_elevation_unit (ft / m) → ft
grade_percent_from_feet Vertical ft over course → % grade
grade_percent_from_meters Vertical m over course → % grade
resolve_grade_percent Normalize gain/loss with grade_input (percent / feet / m)

nrcd.standardize — factors & sport helpers

Name Description
weather_factor Heat slowdown multiplier from temp + dew point (°F)
heat_index, heat_slowdown_percent Hadley-style heat index components
elevation_factor Maurer grade multiplier from % gain/loss
apply_course_grade_factor Grade step on a race time
warn_one_sided_course_grade Warn when only gain or only loss is set
apply_meet_altitude Peronnet meet-altitude correction
peronnet_f_alt, sea_level_time_seconds Altitude factor and sea-level equivalent
resolve_meet_altitude_inputs Parse elevation + barometric pressure from a record
barometric_pressure_hpa_from_record hPa from row fields
barometric_pressure_torr_from_hpa, parse_barometric_pressure_hpa Pressure unit helpers
riegel_convert, riegel_exponent Distance conversion
xc_target_distance_m Config helper for target distance in meters (8000m M / 6000m F)
apply_factors Multiply time by weather/grade/altitude/track/wind factors
is_cross_country, is_track, is_outdoor_track, is_indoor_track Sport name checks
normalize_sport_name, pipeline_kind Sport string normalization / xc vs track

nrcd.data — Zenodo CSV helpers

Name Description
meet_altitude_column Altitude column name in a meet DataFrame
meet_altitude_ft_from_record Meet altitude (ft) from a merged row + course details
derive_course_details_fields Derived weather/grade fields from course details

nrcd.enrich — optional APIs (pip install "nrcd[apis]")

Name Description
API_GUIDE Full signup guide (text); see also API keys guide
EnrichConfig Throttle intervals, cache TTL, API keys
api_keys_from_env Load keys from environment
fetch_weather Temperature, dew point, humidity, AQI — global with lat/lon; US city/state by default
lookup_altitude_ft, lookup_altitude_detail, lookup_elevation_ft Meet altitude (USGS EPQS, ft) — US city/state path; set meet_elevation for non-US
enrich_race_context, enrich_race_context_result Backfill a RaceContext in place
run_enrich_jobs, EnrichJob, JobResult Batch enrichment with thread pool
EnrichResult, ApiUsage, WeatherData, AltitudeResult Result / usage dataclasses
cache_stats, clear_enrich_cache, reset_throttle_state Cache and rate-limit controls
AQI_HISTORY_AVAILABLE_FROM, AQI_HISTORY_AVAILABLE_UNIX AQI history window constants

Citation

NRCD: An Open Database of Collegiate Running with Unified Performance Standardization
Jonathan A. Karr Jr, Ryan M. Fryer, Ben Darden, Nicholas Pell, Kayla Ambrose, Evan Hall, Ramzi K. Bualuan, and Nitesh V. Chawla.
arXiv preprint (forthcoming).

Dataset (if using Zenodo export): Zenodo dataset

Author

Jonathan Karr ORCID Email

Development

pytest

See Changelog. Package version: src/nrcd/init.py (__version__).

License: MIT

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

nrcd-0.1.1.tar.gz (57.4 kB view details)

Uploaded Source

Built Distribution

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

nrcd-0.1.1-py3-none-any.whl (54.0 kB view details)

Uploaded Python 3

File details

Details for the file nrcd-0.1.1.tar.gz.

File metadata

  • Download URL: nrcd-0.1.1.tar.gz
  • Upload date:
  • Size: 57.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for nrcd-0.1.1.tar.gz
Algorithm Hash digest
SHA256 57674bc257fab4fadf97f5d58522c99636879a2e3a205205ee7d9183b311310e
MD5 6cf378e5f8feb34dfb86cae32cc9b906
BLAKE2b-256 6aac0fa0eaeb32396623dd085e721394f0b2fea58b455f89125e9a46d41dfb60

See more details on using hashes here.

Provenance

The following attestation bundles were made for nrcd-0.1.1.tar.gz:

Publisher: publish.yml on National-Running-Club-Database/nrcd

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file nrcd-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: nrcd-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 54.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for nrcd-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 70839e2f178e74d8afb1c3efb77932a7038075f8a58c546bc643ae06d85d2ed5
MD5 0bae1d5682484e4cf60fb32604be3829
BLAKE2b-256 6cd00cb86e4d64d325b484393e168d4025d0873320da6f050be76032f284707e

See more details on using hashes here.

Provenance

The following attestation bundles were made for nrcd-0.1.1-py3-none-any.whl:

Publisher: publish.yml on National-Running-Club-Database/nrcd

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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