Skip to content

betting_combat.rounds.features.checks

Checks on the built round datasets. Each check recomputes something the build produced by a different, slower route, or states an invariant that must hold. Returns a structured report (CheckReport) a job or dashboard can store and alert on; CheckReport.text() is the research’s printout.

rows and targets rows per fight = rounds started; round_idx 0..n-1; one finish row, the last; targets constant within a fight; A/B random; W/L results only as-of features n_fights and momentum (h=2) recomputed by brute force for sampled rows round stats cumulative A-B significant strikes = the rounds before (the research’s 400-fight sample, and every row); Group 3 zero at round 0 matchup symmetry every d_x = x_a - x_b leak scan no input almost determines a target (|corr| > 0.8 flagged) missingness a blank must not predict the result beyond the market’s price model features the walk-forward clock is calibrated every year, never degenerate live markets Kalshi / Polymarket on the right side and clock set 3 no empty cells; the book price = Set 1’s Kalshi price; window sums recomputed from the raw trades before the row coverage per year: fights, round rows, the share with each price source

Every check takes its tables as arguments (nothing reads a file). passed is None where the research states no rule (a number to look at).

Research: ufc/dataset/checks.py and ufc/dataset/report.py (data_section: the coverage table and the column counts). Where the research left an order to a sort’s tie handling (the 400 fights of the round-stats check) or to Python’s hashing (the result set), the order here is fixed; the numbers are the research’s. One check is added (cum_sig_l_all_rows): the research’s round-stats sample cannot fail.

Classes

Check

One result: section and name identify it, value is the measurement, passed True / False where a rule exists (None: informational), line the text.

CheckReport

section

section(name: str) -> list[Check]

text

text() -> str

The research’s printout: ’== section’ then every line indented.

to_frame

to_frame() -> pd.DataFrame

Functions

check_asof

check_asof(fp: pd.DataFrame, fights_long: pd.DataFrame, n: int = 300, seed: int = 0) -> list[Check]

Recompute n_fights and mom_h2 for n sampled fighter rows by brute force from fights_long (FighterHistory.fights_long: fighter_id, date, won, lost).

check_leak_scan

check_leak_scan(d2: pd.DataFrame, catalogue: pd.DataFrame, targets: Sequence[str] = LEAK_TARGETS) -> list[Check]

No model input should almost determine a target: the two numeric columns (targets and live prices left out) with the largest |corr| per target; above 0.8 fails.

check_markets

check_markets(d1: pd.DataFrame) -> list[Check]

Live prices: on the right side (A) and the right clock.

check_missingness

check_missingness(d1: pd.DataFrame) -> list[Check]

For every fighter-A column blank on > 0.5 % of pre-fight rows with a market price: A’s win rate on the blank rows minus the market’s price there; > 3 standard errors fails (’<— LOOK’).

check_model_features

check_model_features(d1: pd.DataFrame) -> list[Check]

Walk-forward model outputs: calibrated on average every year, never degenerate.

check_round_stats

check_round_stats(d2: pd.DataFrame, round_stats: pd.DataFrame, catalogue: pd.DataFrame, n_fights: int = 400) -> list[Check]

round_stats: RawData.round_stats (fight_id, round, slot, sig_l). A fight’s last row must carry the A-B significant strikes of the rounds before it (the research’s check: the first n_fights fights by their last row’s round, ties in data order; those are first-round finishes, where both sides are 0) and so must every row (added here).

check_rows

check_rows(d1: pd.DataFrame, bouts: pd.DataFrame) -> list[Check]

bouts: RawData.bouts (fight_id, kind, sched_rounds, finish_round).

check_set3

check_set3(set3_main: pd.DataFrame, set3_side: pd.DataFrame, d1: pd.DataFrame, trades_main: pd.DataFrame, fights: pd.DataFrame, n: int = 200, seed: int = 0) -> list[Check]

Set 3: no empty cells; the book price = Set 1’s Kalshi price; the last round’s traded dollars recomputed by brute force from the raw trades before the row (n sampled rows). trades_main: fight_id, ts, dollars; fights: fight_id, start (the clock).

check_symmetry

check_symmetry(d1: pd.DataFrame) -> list[Check]

Every d_ column must equal its _a minus _b pair where one exists (blanks as 0).

column_groups

column_groups(catalogue: pd.DataFrame) -> pd.DataFrame

Columns per (group, when known), and which datasets carry them (the stats-feed columns are Dataset 2 only).

coverage_by_year

coverage_by_year(d1: pd.DataFrame) -> pd.DataFrame

Per year: fights, round rows, and the share of fights with each source (pre-fight odds, method odds, Wikipedia card segment, judges, Kalshi, Polymarket), and the split.

run_checks

run_checks(d1: pd.DataFrame, d2: pd.DataFrame, fp: pd.DataFrame, catalogue: pd.DataFrame, bouts: pd.DataFrame, round_stats: pd.DataFrame, fights_long: pd.DataFrame, set3_main: pd.DataFrame | None = None, set3_side: pd.DataFrame | None = None, trades_main: pd.DataFrame | None = None, fights: pd.DataFrame | None = None) -> CheckReport

Every check in the research’s order (Set 3 only when its tables are given).