nrcd 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nrcd-0.1.0/.github/workflows/ci.yml +42 -0
- nrcd-0.1.0/.github/workflows/publish.yml +25 -0
- nrcd-0.1.0/.gitignore +25 -0
- nrcd-0.1.0/CHANGELOG.md +13 -0
- nrcd-0.1.0/CITATION.cff +36 -0
- nrcd-0.1.0/LICENSE +21 -0
- nrcd-0.1.0/PKG-INFO +342 -0
- nrcd-0.1.0/README.md +308 -0
- nrcd-0.1.0/data/README.md +7 -0
- nrcd-0.1.0/docs/API_KEYS.md +153 -0
- nrcd-0.1.0/examples/README.md +41 -0
- nrcd-0.1.0/examples/compare_improvement.py +37 -0
- nrcd-0.1.0/examples/load_dataset_example.py +69 -0
- nrcd-0.1.0/examples/race_context_example.py +68 -0
- nrcd-0.1.0/examples/standardize_one_result.py +28 -0
- nrcd-0.1.0/examples/track_compare_meets.py +76 -0
- nrcd-0.1.0/examples/track_indoor_examples.py +87 -0
- nrcd-0.1.0/examples/track_outdoor_examples.py +151 -0
- nrcd-0.1.0/examples/xc_examples.py +123 -0
- nrcd-0.1.0/local_api_keys.env.example +27 -0
- nrcd-0.1.0/pyproject.toml +73 -0
- nrcd-0.1.0/src/nrcd/__init__.py +28 -0
- nrcd-0.1.0/src/nrcd/data/__init__.py +16 -0
- nrcd-0.1.0/src/nrcd/data/schema.py +94 -0
- nrcd-0.1.0/src/nrcd/enrich/__init__.py +53 -0
- nrcd-0.1.0/src/nrcd/enrich/altitude.py +138 -0
- nrcd-0.1.0/src/nrcd/enrich/api_usage.py +67 -0
- nrcd-0.1.0/src/nrcd/enrich/batch.py +86 -0
- nrcd-0.1.0/src/nrcd/enrich/cache.py +97 -0
- nrcd-0.1.0/src/nrcd/enrich/config.py +37 -0
- nrcd-0.1.0/src/nrcd/enrich/context.py +163 -0
- nrcd-0.1.0/src/nrcd/enrich/geocode.py +63 -0
- nrcd-0.1.0/src/nrcd/enrich/guide.py +81 -0
- nrcd-0.1.0/src/nrcd/enrich/http.py +28 -0
- nrcd-0.1.0/src/nrcd/enrich/throttle.py +32 -0
- nrcd-0.1.0/src/nrcd/enrich/timezone_lookup.py +59 -0
- nrcd-0.1.0/src/nrcd/enrich/weather.py +296 -0
- nrcd-0.1.0/src/nrcd/py.typed +0 -0
- nrcd-0.1.0/src/nrcd/standardize/__init__.py +156 -0
- nrcd-0.1.0/src/nrcd/standardize/altitude.py +283 -0
- nrcd-0.1.0/src/nrcd/standardize/config.py +58 -0
- nrcd-0.1.0/src/nrcd/standardize/context.py +187 -0
- nrcd-0.1.0/src/nrcd/standardize/events.py +92 -0
- nrcd-0.1.0/src/nrcd/standardize/factors.py +94 -0
- nrcd-0.1.0/src/nrcd/standardize/grade.py +80 -0
- nrcd-0.1.0/src/nrcd/standardize/pipeline.py +502 -0
- nrcd-0.1.0/src/nrcd/standardize/reference.py +340 -0
- nrcd-0.1.0/src/nrcd/standardize/sport.py +50 -0
- nrcd-0.1.0/src/nrcd/standardize/time.py +65 -0
- nrcd-0.1.0/src/nrcd/standardize/track.py +179 -0
- nrcd-0.1.0/src/nrcd/standardize/units.py +164 -0
- nrcd-0.1.0/src/nrcd/standardize/validation.py +53 -0
- nrcd-0.1.0/src/nrcd/standardize/wind.py +132 -0
- nrcd-0.1.0/tests/conftest.py +7 -0
- nrcd-0.1.0/tests/live_api_config.py +109 -0
- nrcd-0.1.0/tests/test_altitude_barometric.py +52 -0
- nrcd-0.1.0/tests/test_enrich.py +139 -0
- nrcd-0.1.0/tests/test_enrich_api_usage.py +30 -0
- nrcd-0.1.0/tests/test_enrich_batch.py +23 -0
- nrcd-0.1.0/tests/test_enrich_cache_throttle.py +65 -0
- nrcd-0.1.0/tests/test_enrich_live_openweather.py +148 -0
- nrcd-0.1.0/tests/test_events.py +68 -0
- nrcd-0.1.0/tests/test_grade_warning.py +49 -0
- nrcd-0.1.0/tests/test_live_api_config.py +24 -0
- nrcd-0.1.0/tests/test_nrcd_schema.py +34 -0
- nrcd-0.1.0/tests/test_packaging.py +24 -0
- nrcd-0.1.0/tests/test_sport_and_docs.py +104 -0
- nrcd-0.1.0/tests/test_standardize.py +244 -0
- nrcd-0.1.0/tests/test_standardize_result.py +41 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, master]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main, master]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ["3.10", "3.11", "3.12"]
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
- uses: actions/setup-python@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: ${{ matrix.python-version }}
|
|
20
|
+
- name: Install package and test deps
|
|
21
|
+
run: |
|
|
22
|
+
python -m pip install --upgrade pip
|
|
23
|
+
pip install -e ".[dev]"
|
|
24
|
+
- name: Ruff
|
|
25
|
+
run: ruff check src tests examples
|
|
26
|
+
- name: Run tests
|
|
27
|
+
run: pytest -q
|
|
28
|
+
- name: Smoke-run examples
|
|
29
|
+
run: |
|
|
30
|
+
for script in \
|
|
31
|
+
examples/xc_examples.py \
|
|
32
|
+
examples/track_outdoor_examples.py \
|
|
33
|
+
examples/track_indoor_examples.py \
|
|
34
|
+
examples/track_compare_meets.py \
|
|
35
|
+
examples/compare_improvement.py \
|
|
36
|
+
examples/race_context_example.py \
|
|
37
|
+
examples/standardize_one_result.py; do
|
|
38
|
+
python "$script"
|
|
39
|
+
done
|
|
40
|
+
# load_dataset_example.py requires optional Zenodo CSVs (pip install "nrcd[data]")
|
|
41
|
+
- name: Build wheel
|
|
42
|
+
run: pip install build && python -m build
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
publish:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
environment: pypi
|
|
12
|
+
permissions:
|
|
13
|
+
id-token: write
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
- uses: actions/setup-python@v5
|
|
17
|
+
with:
|
|
18
|
+
python-version: "3.12"
|
|
19
|
+
- name: Build package
|
|
20
|
+
run: |
|
|
21
|
+
python -m pip install --upgrade pip
|
|
22
|
+
pip install build twine
|
|
23
|
+
python -m build
|
|
24
|
+
twine check dist/*
|
|
25
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
nrcd-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Dataset (download from Zenodo; see data/README.md)
|
|
2
|
+
data/*.csv
|
|
3
|
+
|
|
4
|
+
# Python
|
|
5
|
+
__pycache__/
|
|
6
|
+
*.py[cod]
|
|
7
|
+
*$py.class
|
|
8
|
+
.Python
|
|
9
|
+
.env
|
|
10
|
+
local_api_keys.env
|
|
11
|
+
.venv
|
|
12
|
+
venv/
|
|
13
|
+
ENV/
|
|
14
|
+
dist/
|
|
15
|
+
build/
|
|
16
|
+
*.egg-info/
|
|
17
|
+
|
|
18
|
+
# Test / tooling
|
|
19
|
+
.pytest_cache/
|
|
20
|
+
.mypy_cache/
|
|
21
|
+
|
|
22
|
+
# OS / editor
|
|
23
|
+
.DS_Store
|
|
24
|
+
.idea/
|
|
25
|
+
.vscode/
|
nrcd-0.1.0/CHANGELOG.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.1.0] - 2026-06-06
|
|
4
|
+
|
|
5
|
+
Initial release.
|
|
6
|
+
|
|
7
|
+
- Sport-specific entry points — `standardize_xc`, `standardize_road`, `standardize_outdoor_track`, `standardize_indoor_track` (plus low-level `standardize_result`)
|
|
8
|
+
- Clock-string times and flexible distance/units (m, km, mi; °F/°C; ft/m)
|
|
9
|
+
- `nrcd.enrich` — optional weather and meet-altitude API backfill
|
|
10
|
+
- `nrcd.data` — Zenodo CSV helpers (`pip install "nrcd[data]"`)
|
|
11
|
+
- Examples, docs, and tests
|
|
12
|
+
|
|
13
|
+
[0.1.0]: https://github.com/National-Running-Club-Database/nrcd/releases/tag/v0.1.0
|
nrcd-0.1.0/CITATION.cff
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
title: "nrcd: NRCD performance standardization library"
|
|
3
|
+
message: "If you use this software or the NRCD standardization formulas, please cite the paper."
|
|
4
|
+
type: software
|
|
5
|
+
version: 0.1.0
|
|
6
|
+
date-released: 2026-06-06
|
|
7
|
+
license: MIT
|
|
8
|
+
repository-code: "https://github.com/National-Running-Club-Database/nrcd"
|
|
9
|
+
url: "https://github.com/National-Running-Club-Database/nrcd"
|
|
10
|
+
authors:
|
|
11
|
+
- family-names: Karr
|
|
12
|
+
given-names: Jonathan A.
|
|
13
|
+
name-particle: Jr
|
|
14
|
+
- family-names: Fryer
|
|
15
|
+
given-names: Ryan M.
|
|
16
|
+
- family-names: Darden
|
|
17
|
+
given-names: Ben
|
|
18
|
+
- family-names: Pell
|
|
19
|
+
given-names: Nicholas
|
|
20
|
+
- family-names: Ambrose
|
|
21
|
+
given-names: Kayla
|
|
22
|
+
- family-names: Hall
|
|
23
|
+
given-names: Evan
|
|
24
|
+
- family-names: Bualuan
|
|
25
|
+
given-names: Ramzi K.
|
|
26
|
+
- family-names: Chawla
|
|
27
|
+
given-names: Nitesh V.
|
|
28
|
+
preferred-citation:
|
|
29
|
+
type: article
|
|
30
|
+
title: "NRCD: An Open Database of Collegiate Running with Unified Performance Standardization"
|
|
31
|
+
year: 2026
|
|
32
|
+
notes: "arXiv preprint forthcoming"
|
|
33
|
+
identifiers:
|
|
34
|
+
- type: url
|
|
35
|
+
value: "https://zenodo.org/records/17917357"
|
|
36
|
+
description: "NRCD dataset export (optional)"
|
nrcd-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 National Running Club Database
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
nrcd-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nrcd
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: NRCD performance standardization formulas (cross country, track, road)
|
|
5
|
+
Project-URL: Homepage, https://github.com/National-Running-Club-Database/nrcd
|
|
6
|
+
Project-URL: Repository, https://github.com/National-Running-Club-Database/nrcd
|
|
7
|
+
Project-URL: Documentation, https://github.com/National-Running-Club-Database/nrcd#readme
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/National-Running-Club-Database/nrcd/issues
|
|
9
|
+
Project-URL: Dataset, https://zenodo.org/records/17917357
|
|
10
|
+
Author: Ryan M. Fryer, Ben Darden, Nicholas Pell, Kayla Ambrose, Evan Hall, Ramzi K. Bualuan, Nitesh V. Chawla
|
|
11
|
+
Author-email: "Jonathan A. Karr Jr" <jkarr@nd.edu>
|
|
12
|
+
License-Expression: MIT
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Keywords: cross-country,running,sports-analytics,standardization
|
|
15
|
+
Classifier: Development Status :: 3 - Alpha
|
|
16
|
+
Classifier: Intended Audience :: Science/Research
|
|
17
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Provides-Extra: apis
|
|
25
|
+
Requires-Dist: requests>=2.28.0; extra == 'apis'
|
|
26
|
+
Provides-Extra: data
|
|
27
|
+
Requires-Dist: pandas>=2.0.0; extra == 'data'
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pandas>=2.0.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: requests>=2.28.0; extra == 'dev'
|
|
32
|
+
Requires-Dist: ruff>=0.4.0; extra == 'dev'
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
# nrcd
|
|
36
|
+
|
|
37
|
+
Python library for **National Running Club Database (NRCD)** performance standardization (cross country, track, road). Implements the formulas documented in the NRCD resource paper.
|
|
38
|
+
|
|
39
|
+
[](https://github.com/National-Running-Club-Database/nrcd)
|
|
40
|
+
[](https://www.python.org/downloads/)
|
|
41
|
+
[](https://pypi.org/project/nrcd/)
|
|
42
|
+
[](LICENSE)
|
|
43
|
+
[](https://github.com/National-Running-Club-Database/nrcd/actions/workflows/ci.yml)
|
|
44
|
+
|
|
45
|
+
Use this to **standardize your own race results** — no NRCD dataset download required.
|
|
46
|
+
|
|
47
|
+
## Quick start
|
|
48
|
+
|
|
49
|
+
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).
|
|
50
|
+
|
|
51
|
+
**Cross country — 5K in 22:15**
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from nrcd import standardize_xc # or: from nrcd.standardize import standardize_xc
|
|
55
|
+
|
|
56
|
+
std = standardize_xc("22:15", gender="M", reported_distance="5k")
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**Cross country — 8 km with weather, grade, altitude**
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
std = standardize_xc(
|
|
63
|
+
"27:30",
|
|
64
|
+
gender="M",
|
|
65
|
+
reported_distance=8,
|
|
66
|
+
distance_unit="km",
|
|
67
|
+
actual_distance=8.01,
|
|
68
|
+
temperature=72, # °F (default)
|
|
69
|
+
dew_point=65,
|
|
70
|
+
elevation_gain=2.5, # % grade (default)
|
|
71
|
+
elevation_loss=2.5,
|
|
72
|
+
meet_elevation=5200, # feet (default)
|
|
73
|
+
)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**Outdoor track — 100m with wind**
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
from nrcd import standardize_outdoor_track
|
|
80
|
+
|
|
81
|
+
std = standardize_outdoor_track(
|
|
82
|
+
"13.52",
|
|
83
|
+
gender="F",
|
|
84
|
+
event_name="100m",
|
|
85
|
+
wind_mps=2.0,
|
|
86
|
+
)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Indoor track — 200m on a banked 200m oval**
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
from nrcd import standardize_indoor_track
|
|
93
|
+
|
|
94
|
+
std = standardize_indoor_track(
|
|
95
|
+
"21.80",
|
|
96
|
+
gender="M",
|
|
97
|
+
event_name="200m",
|
|
98
|
+
lap_length_m=200,
|
|
99
|
+
banked=True,
|
|
100
|
+
)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**Road — half marathon with weather and grade**
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
from nrcd import standardize_road
|
|
107
|
+
|
|
108
|
+
std = standardize_road(
|
|
109
|
+
"1:25:30",
|
|
110
|
+
gender="F",
|
|
111
|
+
event_name="Half Marathon",
|
|
112
|
+
temperature=55,
|
|
113
|
+
dew_point=48,
|
|
114
|
+
elevation_gain=1.2,
|
|
115
|
+
elevation_loss=1.2,
|
|
116
|
+
)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Pipelines
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
| Sport | Function | What differs |
|
|
123
|
+
| ------------- | --------------------------- | --------------------------------------------------------------------------------------- |
|
|
124
|
+
| Cross country | `standardize_xc` | Weather, grade, altitude, then **Riegel to NIRCA 8k/6k** |
|
|
125
|
+
| Road | `standardize_road` | Same weather / grade / altitude as XC; distance from `event_name`; **no Riegel target** |
|
|
126
|
+
| Outdoor track | `standardize_outdoor_track` | Sprint **wind**, weather, grade, altitude |
|
|
127
|
+
| Indoor track | `standardize_indoor_track` | **Lap/bank venue** factors; no wind |
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
`standardize_result` remains available when you need a custom `sport_name` string.
|
|
131
|
+
|
|
132
|
+
**Unit switches** (optional kwargs on all pipelines):
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
| Field | Default | Alternative |
|
|
136
|
+
| ---------------------------------- | ----------- | ----------------------------- |
|
|
137
|
+
| `temperature`, `dew_point` | **°F** | `temp_unit="C"` |
|
|
138
|
+
| `meet_elevation` | **feet** | `venue_elevation_unit="m"` |
|
|
139
|
+
| `elevation_gain`, `elevation_loss` | **% grade** | `grade_input="feet"` or `"m"` |
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
### More examples
|
|
143
|
+
|
|
144
|
+
Runnable scripts in [examples/](examples/):
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
| | Script |
|
|
148
|
+
| ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
149
|
+
| XC | [xc_examples.py](examples/xc_examples.py), [compare_improvement.py](examples/compare_improvement.py), [standardize_one_result.py](examples/standardize_one_result.py) |
|
|
150
|
+
| Track | [track_outdoor_examples.py](examples/track_outdoor_examples.py), [track_indoor_examples.py](examples/track_indoor_examples.py), [track_compare_meets.py](examples/track_compare_meets.py) |
|
|
151
|
+
| Both | [race_context_example.py](examples/race_context_example.py), [load_dataset_example.py](examples/load_dataset_example.py) |
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
`load_dataset_example.py` exits with code 1 if Zenodo CSVs are not in `data/` — that is expected without the optional dataset.
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
pip install nrcd
|
|
158
|
+
python examples/xc_examples.py
|
|
159
|
+
python examples/track_outdoor_examples.py
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Install
|
|
163
|
+
|
|
164
|
+
Requires Python 3.10+.
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
pip install nrcd # after first PyPI release
|
|
168
|
+
pip install "nrcd[apis]" # optional: weather / elevation APIs
|
|
169
|
+
pip install "nrcd[data]" # optional: Zenodo CSV helpers (pandas)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Until the package is on PyPI, install from source:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
git clone https://github.com/National-Running-Club-Database/nrcd
|
|
176
|
+
cd nrcd
|
|
177
|
+
pip install -e .
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
From source (development):
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
git clone https://github.com/National-Running-Club-Database/nrcd
|
|
184
|
+
cd nrcd
|
|
185
|
+
pip install -e ".[dev]"
|
|
186
|
+
pip install -e ".[dev,apis]"
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### API keys (optional — `nrcd.enrich` only)
|
|
190
|
+
|
|
191
|
+
Standardization does **not** need API keys. Use enrichment only when backfilling **weather** or **meet altitude** from city/state.
|
|
192
|
+
|
|
193
|
+
1. `pip install "nrcd[apis]"`
|
|
194
|
+
2. [](https://home.openweathermap.org/users/sign_up) → [](https://home.openweathermap.org/api_keys) → set `NRCD_OPENWEATHER_API_KEY`
|
|
195
|
+
3. For **weather** at a race date/time, also [](https://timezonedb.com/register) → `NRCD_TIMEZONE_API_KEY`
|
|
196
|
+
4. **Meet altitude** uses free USGS EPQS (no key) after OpenWeather geocodes the city
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
export NRCD_OPENWEATHER_API_KEY="your_key"
|
|
200
|
+
export NRCD_TIMEZONE_API_KEY="your_key" # weather only
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**Live tests (optional):** copy `local_api_keys.env.example` → `local_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**.
|
|
204
|
+
|
|
205
|
+
**Full walkthrough:** [](docs/API_KEYS.md). In Python: `from nrcd.enrich import API_GUIDE; print(API_GUIDE)`.
|
|
206
|
+
|
|
207
|
+
Historical OpenWeather timemachine weather may require a **paid** OpenWeather plan; geocoding + USGS altitude often work on the free tier.
|
|
208
|
+
|
|
209
|
+
## Do you need the NRCD dataset?
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
| Use case | Zenodo CSVs needed? |
|
|
213
|
+
| --------------------------------------- | ------------------- |
|
|
214
|
+
| Standardize your own results | **No** |
|
|
215
|
+
| `examples/` scripts | **No** |
|
|
216
|
+
| `nrcd.enrich` API backfill | **No** |
|
|
217
|
+
| `examples/load_dataset_example.py` only | **Yes** (optional) |
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
Optional public export: [](https://zenodo.org/records/17917357) (see [](data/README.md)).
|
|
221
|
+
|
|
222
|
+
## API
|
|
223
|
+
|
|
224
|
+
Full parameter tables: `from nrcd import PARAMETERS_DOC` or `help(nrcd.standardize)`.
|
|
225
|
+
|
|
226
|
+
### Entry points
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
| Function | Use for |
|
|
230
|
+
| --------------------------- | ----------------------------------------------------------------------- |
|
|
231
|
+
| `standardize_xc` | Cross country — distance in m/km/mi; Riegel to NIRCA targets |
|
|
232
|
+
| `standardize_road` | Road / marathon — `event_name`; weather, grade, altitude |
|
|
233
|
+
| `standardize_outdoor_track` | Outdoor track — `event_name`; wind on sprints |
|
|
234
|
+
| `standardize_indoor_track` | Indoor track — `event_name`; lap length / banking |
|
|
235
|
+
| `standardize_result` | Low-level — any `sport_name` (advanced) |
|
|
236
|
+
| `standardize_seconds` | Dispatch from a `RaceContext` / `XCRaceContext` row |
|
|
237
|
+
| `enrich_race_context` | Fill missing weather/altitude on a context (`pip install "nrcd[apis]"`) |
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
### `nrcd.standardize` — pipelines & context
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
| Name | Description |
|
|
244
|
+
| ---------------------------------------------------------------- | ---------------------------------------------------------------- |
|
|
245
|
+
| `RaceContext` | Dataclass for one result (XC or track); `time_str` or `time_sec` |
|
|
246
|
+
| `XCRaceContext` | XC-focused `RaceContext` subclass |
|
|
247
|
+
| `StandardizeConfig` | Paper coefficients (Riegel exponents, heat k, grade bases, …) |
|
|
248
|
+
| `PARAMETERS_DOC` | Full required/optional parameter reference (text) |
|
|
249
|
+
| `PARAMETER_SPECS` | Same metadata as structured `ParameterSpec` tuples |
|
|
250
|
+
| `parameter_specs()` | Return `PARAMETER_SPECS` |
|
|
251
|
+
| `required_for("xc" | "road" | "outdoor_track" | "indoor_track")` | Minimal field names per pipeline |
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
### `nrcd.standardize` — time, distance, units
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
| Name | Description |
|
|
258
|
+
| ---------------------------------- | ----------------------------------------------------------------- |
|
|
259
|
+
| `parse_time` | `"22:15"`, `"1:10:13"`, or seconds → float seconds |
|
|
260
|
+
| `format_time` | Seconds → clock string |
|
|
261
|
+
| `parse_distance` | `"5k"`, `8`, `"8000m"` + unit → meters |
|
|
262
|
+
| `distance_to_meters` | Numeric distance with `distance_unit` (`m` / `km` / `mi`) |
|
|
263
|
+
| `c_to_f`, `f_to_c` | Temperature conversion |
|
|
264
|
+
| `feet_to_meters`, `meters_to_feet` | Length conversion |
|
|
265
|
+
| `temperature_to_fahrenheit` | Value + `temp_unit` (`F` / `C`) → °F |
|
|
266
|
+
| `venue_elevation_to_feet` | Meet altitude + `venue_elevation_unit` (`ft` / `m`) → ft |
|
|
267
|
+
| `grade_percent_from_feet` | Vertical ft over course → % grade |
|
|
268
|
+
| `grade_percent_from_meters` | Vertical m over course → % grade |
|
|
269
|
+
| `resolve_grade_percent` | Normalize gain/loss with `grade_input` (`percent` / `feet` / `m`) |
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
### `nrcd.standardize` — factors & sport helpers
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
| Name | Description |
|
|
276
|
+
| --------------------------------------------------------------------- | ---------------------------------------------------------- |
|
|
277
|
+
| `weather_factor` | Heat slowdown multiplier from temp + dew point (°F) |
|
|
278
|
+
| `heat_index`, `heat_slowdown_percent` | Hadley-style heat index components |
|
|
279
|
+
| `elevation_factor` | Maurer grade multiplier from % gain/loss |
|
|
280
|
+
| `apply_course_grade_factor` | Grade step on a race time |
|
|
281
|
+
| `warn_one_sided_course_grade` | Warn when only gain or only loss is set |
|
|
282
|
+
| `apply_meet_altitude` | Peronnet meet-altitude correction |
|
|
283
|
+
| `peronnet_f_alt`, `sea_level_time_seconds` | Altitude factor and sea-level equivalent |
|
|
284
|
+
| `resolve_meet_altitude_inputs` | Parse elevation + barometric pressure from a record |
|
|
285
|
+
| `barometric_pressure_hpa_from_record` | hPa from row fields |
|
|
286
|
+
| `barometric_pressure_torr_from_hpa`, `parse_barometric_pressure_hpa` | Pressure unit helpers |
|
|
287
|
+
| `riegel_convert`, `riegel_exponent` | Distance conversion |
|
|
288
|
+
| `xc_target_distance_m` | NIRCA reference XC distance (8000 M / 6000 F) |
|
|
289
|
+
| `apply_factors` | Multiply time by weather/grade/altitude/track/wind factors |
|
|
290
|
+
| `is_cross_country`, `is_track`, `is_outdoor_track`, `is_indoor_track` | Sport name checks |
|
|
291
|
+
| `normalize_sport_name`, `pipeline_kind` | Sport string normalization / `xc` vs `track` |
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
### `nrcd.data` — Zenodo CSV helpers
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
| Name | Description |
|
|
298
|
+
| ------------------------------ | ----------------------------------------------------- |
|
|
299
|
+
| `meet_altitude_column` | Altitude column name in a meet DataFrame |
|
|
300
|
+
| `meet_altitude_ft_from_record` | Meet altitude (ft) from a merged row + course details |
|
|
301
|
+
| `derive_course_details_fields` | Derived weather/grade fields from course details |
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
### `nrcd.enrich` — optional APIs (`pip install "nrcd[apis]"`)
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
| Name | Description |
|
|
308
|
+
| --------------------------------------------------------------------- | ------------------------------------------------------------------------- |
|
|
309
|
+
| `API_GUIDE` | Full signup guide (text); see also [](docs/API_KEYS.md) |
|
|
310
|
+
| `EnrichConfig` | Throttle intervals, cache TTL, API keys |
|
|
311
|
+
| `api_keys_from_env` | Load keys from environment |
|
|
312
|
+
| `fetch_weather` | Temperature, dew point, humidity, AQI for city/state + date |
|
|
313
|
+
| `lookup_altitude_ft`, `lookup_altitude_detail`, `lookup_elevation_ft` | Meet altitude (USGS EPQS, ft) |
|
|
314
|
+
| `enrich_race_context`, `enrich_race_context_result` | Backfill a `RaceContext` in place |
|
|
315
|
+
| `run_enrich_jobs`, `EnrichJob`, `JobResult` | Batch enrichment with thread pool |
|
|
316
|
+
| `EnrichResult`, `ApiUsage`, `WeatherData`, `AltitudeResult` | Result / usage dataclasses |
|
|
317
|
+
| `cache_stats`, `clear_enrich_cache`, `reset_throttle_state` | Cache and rate-limit controls |
|
|
318
|
+
| `AQI_HISTORY_AVAILABLE_FROM`, `AQI_HISTORY_AVAILABLE_UNIX` | AQI history window constants |
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
## Citation
|
|
322
|
+
|
|
323
|
+
> **NRCD: An Open Database of Collegiate Running with Unified Performance Standardization**
|
|
324
|
+
> Jonathan A. Karr Jr, Ryan M. Fryer, Ben Darden, Nicholas Pell, Kayla Ambrose, Evan Hall, Ramzi K. Bualuan, and Nitesh V. Chawla.
|
|
325
|
+
> arXiv preprint (forthcoming).
|
|
326
|
+
|
|
327
|
+
Dataset (if using Zenodo export): [](https://zenodo.org/records/17917357)
|
|
328
|
+
|
|
329
|
+
## Author
|
|
330
|
+
|
|
331
|
+
[](https://orcid.org/0009-0000-1600-6122)
|
|
332
|
+
[](mailto:jkarr@nd.edu)
|
|
333
|
+
|
|
334
|
+
## Development
|
|
335
|
+
|
|
336
|
+
```bash
|
|
337
|
+
pytest
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
See [](CHANGELOG.md). Package version: [](src/nrcd/__init__.py) (`__version__`).
|
|
341
|
+
|
|
342
|
+
[](LICENSE)
|