Spaces:
Configuration error
Configuration error
Download trifecta_bro/model/pace_analysis.py from Brettapps/Trifecta-Lab: direct link, hf CLI and curl.
- Browser
- Download file 2.87 kB
-
https://huggingface.co/spaces/Brettapps/Trifecta-Lab/resolve/main/trifecta_bro/model/pace_analysis.py
- Command line
-
hf download hf://spaces/Brettapps/Trifecta-Lab/trifecta_bro/model/pace_analysis.py
-
curl -L -o pace_analysis.py https://huggingface.co/spaces/Brettapps/Trifecta-Lab/resolve/main/trifecta_bro/model/pace_analysis.py
2.87 kB
| """Pace / race-shape estimation. | |
| Where FormFav supplies a pace scenario we use it; otherwise we derive a proxy | |
| from the field's historical speed profiles. The engine then classifies SLOW / | |
| MODERATE / FAST / VERY FAST and tags each runner's likely role | |
| (leader / on-speed / midfield / backmarker) using barrier + historical | |
| front-running tendency when available. | |
| All adjustments are evidence-based and never universal rules. | |
| """ | |
| from __future__ import annotations | |
| from typing import Optional | |
| from ..data.models import RaceModel, RunnerModel | |
| def classify_pace(race: RaceModel, runners: list[RunnerModel]) -> dict: | |
| """Estimate race shape from available evidence. | |
| Uses: | |
| - FormFav raceClass / distance as coarse tempo priors (short races + lower | |
| classes tend to be faster) | |
| - a derived 'speed_pressure' from how many runners have strong front-running | |
| or high win% (proxy when no explicit pace field) | |
| """ | |
| n = len(runners) or 1 | |
| pressure = 0.0 | |
| leaders = [] | |
| for r in runners: | |
| wp = r.win_percent | |
| # high win% + low barrier => more likely to press forward | |
| barrier = r.barrier or 5 | |
| fwd = max(0.0, (wp / 100.0) - 0.05) + (0.5 if barrier <= 3 else 0.0) | |
| pressure += fwd | |
| if fwd > 0.12: | |
| leaders.append(r.number) | |
| pressure_norm = pressure / n # ~0..0.5 | |
| if pressure_norm >= 0.30: | |
| label = "VERY FAST" | |
| elif pressure_norm >= 0.20: | |
| label = "FAST" | |
| elif pressure_norm >= 0.11: | |
| label = "MODERATE" | |
| else: | |
| label = "SLOW" | |
| roles = {} | |
| for r in runners: | |
| barrier = r.barrier or 5 | |
| wp = r.win_percent / 100.0 | |
| if barrier <= 3 and wp >= 0.10: | |
| roles[r.number] = "leader/on-speed" | |
| elif barrier <= 6: | |
| roles[r.number] = "midfield" | |
| else: | |
| roles[r.number] = "backmarker" | |
| return { | |
| "label": label, | |
| "pressure": round(pressure_norm, 3), | |
| "likely_leaders": leaders, | |
| "roles": roles, | |
| } | |
| def pace_adjustment(runner: RunnerModel, pace: dict) -> float: | |
| """Return an additive 0..100 sub-score adjustment (can be negative). | |
| Logic: | |
| - SLOW race: a confirmed leader/on-speed runner is advantaged (can control). | |
| - FAST/VERY FAST: a leader is penalised (likely to fold); midfield/strong | |
| finishers advantaged. | |
| - Backmarkers get a small negative in SLOW (hard to make ground). | |
| """ | |
| role = pace["roles"].get(runner.number, "midfield") | |
| label = pace["label"] | |
| if label == "SLOW": | |
| if role == "leader/on-speed": | |
| return 6.0 | |
| if role == "backmarker": | |
| return -4.0 | |
| return 1.0 | |
| if label in ("FAST", "VERY FAST"): | |
| if role == "leader/on-speed": | |
| return -4.0 | |
| if role == "backmarker": | |
| return 3.0 | |
| return 2.0 | |
| return 0.0 | |