Skip to main content

MBB — additional Python functions — Models and calculators: AssistEvent–build_priors

AssistEvent​

AssistEvent(player_code: 'str', count: 'ShotClockStats' = <factory>) -> None

One assist relationship's counts (LineupEventStats.AssistEvent,

LineupEventStats.scala:64-67).

Parameters

ParameterTypeDefaultDescription
player_codestrThe other player in the assist event (by code).
countShotClockStats<factory>The assist counts, by shot-clock segment.

AssistInfo​

AssistInfo(counts: 'ShotClockStats' = <factory>, target: 'Optional[list[AssistEvent]]' = None, source: 'Optional[list[AssistEvent]]' = None) -> None

Detailed assist info, split into given/received

(LineupEventStats.AssistInfo, LineupEventStats.scala:87-91).

Parameters

ParameterTypeDefaultDescription
countsShotClockStats<factory>Raw assist statistics.
targetOptional[list[AssistEvent]]NonePlayers "I" assisted, if tracked.
sourceOptional[list[AssistEvent]]NonePlayers who assisted "me", if tracked.

ConferenceId​

ConferenceId(name: 'str') -> None

CBB conference identifier (ConferenceId, ``models/ConferenceId

.scala:7, AnyVal). **Scope addition, Task 5e.4** -- the first model consumed by mbb_ncaa_team_parsers.py (TeamIdParser.get_team_triples/build_lineup_cli_array/build_available_team_list``). Appended here (not inserted among the 5a-reviewed classes above) to keep this an additive-only change, matching RosterEntry's precedent.

ConferenceId.is_high_major (the companion object's other member, models/ConferenceId.scala:11-16) is NOT ported. It has no call site anywhere in TeamIdParser/TeamScheduleParser (verified: the only other ConferenceId construction sites in the upstream tree are kenpom/TeamParser.scala and BuildIngestPipeline.scala, neither of which is in this port's scope, and neither calls is_high_major either) -- nothing in Phase 5e would exercise it. Noted here rather than silently dropped, matching this module's precedent for other unreferenced companion-object members (see the module docstring's Year.until / Game.Score.by_winner notes).

Parameters

ParameterTypeDefaultDescription
namestrThe unique name of the conference.

CutdownShotEvent​

CutdownShotEvent(loc: 'Optional[ShotLocation]', geo: 'Optional[ShotGeo]', dist: 'Optional[float]', pts: 'int', value: 'int', is_ast: 'Optional[bool]', is_trans: 'Optional[bool]', is_orb: 'Optional[bool]') -> None

A narrowed ShotEvent, keeping only the fields needed once a

shot has been matched to a player/lineup event (CutdownShotEvent, models/ncaa/ShotEvent.scala:31-40). Scope addition, Task 5e.5 -- ported for shape fidelity even though it is dead code in the ENTIRE upstream tree: grepping shows it appears only in its own definition (ShotEvent.scala) and as the never-populated shot_info: Option[CutdownShotEvent] field on PlayerEvent.scala -- it is never constructed anywhere. (PlayByPlayUtils.shot_value is an UNRELATED event_str -> int point-value classifier that merely shares a similar name -- Task 5e.6 will NOT produce this type either.) Appended here (not inserted among the 5a-reviewed classes above) to keep this an additive-only change, matching RosterEntry/ConferenceId's precedent.

Parameters

ParameterTypeDefaultDescription
locOptional[ShotLocation]The shot's court location, in feet, if known.
geoOptional[ShotGeo]The shot's synthetic lat/lon, if known.
distOptional[float]The shot's distance from the basket, in feet, if known.
ptsintThe point value if made (2/3), else 0.
valueintThe shot's attempt value (2/3), regardless of make/miss.
is_astOptional[bool]Whether the shot was assisted, if known.
is_transOptional[bool]Whether the shot was in transition, if known.
is_orbOptional[bool]Whether the shot followed an offensive rebound, if known.

Direction​

Direction(*values)

Which team is in possession (RawGameEvent.Direction, :119-121).

FieldGoalStats​

FieldGoalStats(attempts: 'ShotClockStats' = <factory>, made: 'ShotClockStats' = <factory>, ast: 'Optional[ShotClockStats]' = None) -> None

Field-goal counting stats (LineupEventStats.FieldGoalStats,

LineupEventStats.scala:75-79).

Parameters

ParameterTypeDefaultDescription
attemptsShotClockStats<factory>Shot attempts, successful or not.
madeShotClockStats<factory>Successful shot attempts.
astOptional[ShotClockStats]NoneSuccessful shot attempts that were assisted, if tracked.

LeagueConstants​

LeagueConstants(hfa: 'float', margin_sd: 'float', em_scale: 'float', avg_tempo: 'float', avg_efficiency: 'float', quad_thresholds: 'dict[str, dict[str, int]]', bubble_adj_em: 'float', in_game_wp_artifact: 'str') -> None

Per-league fitted constants for the prediction & tournament stack.

Algorithms in the stack are league-agnostic; every men's/women's-specific number lives here so a WBB caller is a by-reference shim plus this table (the same pattern wbb_rapm / wbb_ratings already use).

Parameters

ParameterTypeDefaultDescription
hfafloatHome-court advantage in points (fitted on the 2024 backtest).
margin_sdfloatStd. dev. of the game-margin residual (fitted on the 2024 backtest; the Brier-minimizing sigma agrees to within 0.04).
em_scalefloatSlope applied to the AdjEM difference when predicting a game margin. AdjEM is per-100-possessions, so a game margin scales by ~tempo/100 (~0.67); the fitted value is lower still because the as-of AdjEM estimate is noisy and the optimal predictive slope is attenuated (regression dilution). Fitted jointly with hfa.
avg_tempofloatLeague baseline possessions per game (adjusted-tempo anchor).
avg_efficiencyfloatLeague baseline points per 100 possessions.
quad_thresholdsdict[str, dict[str, int]]NET-style quadrant opponent-rank upper bounds, keyed by venue (home / neutral / away) then q1 / q2 / q3 (Quad 4 is any opponent ranked worse than q3).
bubble_adj_emfloatAdjEM of a bubble-quality team on THIS engine's scale (mean of engine ranks 40-50 on the fit season) -- the WAB baseline.
in_game_wp_artifactstrFilename of the bundled in-game-WP coefficients under sportsdataverse/mbb/models (fitted + committed in Phase 3).

LineupEvent​

LineupEvent(date: 'datetime', location_type: 'LocationType', start_min: 'float', end_min: 'float', duration_mins: 'float', score_info: 'ScoreInfo', team: 'TeamSeasonId', opponent: 'TeamSeasonId', lineup_id: 'LineupId', players: 'list[PlayerCodeId]', players_in: 'list[PlayerCodeId]', players_out: 'list[PlayerCodeId]', raw_game_events: 'list[RawGameEvent]', team_stats: 'LineupEventStats', opponent_stats: 'LineupEventStats', player_count_error: 'Optional[int]' = None) -> None

A portion of a game during which a given lineup was on the floor

(LineupEvent, LineupEvent.scala:41-58).

Parameters

ParameterTypeDefaultDescription
datedatetimeThe date of the game.
location_typeLocationTypeHome/away/neutral (etc.) for this game.
start_minfloatThe point in the game at which the lineup entered.
end_minfloatThe point in the game at which the lineup changed.
duration_minsfloatThe duration of the lineup.
score_infoScoreInfoThe score differential context for this event.
teamTeamSeasonIdThe team under analysis.
opponentTeamSeasonIdThe opposing team.
lineup_idLineupIdA string that defines the set of players on the floor.
playerslist[PlayerCodeId]Mapping from player code to full identity, for this lineup.
players_inlist[PlayerCodeId]Players who subbed in for this event.
players_outlist[PlayerCodeId]Players who subbed out for this event.
raw_game_eventslist[RawGameEvent]The raw NCAA event strings for both teams.
team_statsLineupEventStatsNumerical stats extracted for the lineup (team side).
opponent_statsLineupEventStatsNumerical stats extracted for the lineup (opponent side).
player_count_errorOptional[int]NoneIf the lineup is "impossible", the number of players actually seen (for analysis purposes).

LineupEventStats​

LineupEventStats(num_events: 'int' = 0, num_possessions: 'int' = 0, fg: 'FieldGoalStats' = <factory>, fg_rim: 'FieldGoalStats' = <factory>, fg_mid: 'FieldGoalStats' = <factory>, fg_2p: 'FieldGoalStats' = <factory>, fg_3p: 'FieldGoalStats' = <factory>, ft: 'FieldGoalStats' = <factory>, orb: 'Optional[ShotClockStats]' = None, drb: 'Optional[ShotClockStats]' = None, to: 'ShotClockStats' = <factory>, stl: 'Optional[ShotClockStats]' = None, blk: 'Optional[ShotClockStats]' = None, assist: 'Optional[ShotClockStats]' = None, ast_rim: 'Optional[AssistInfo]' = None, ast_mid: 'Optional[AssistInfo]' = None, ast_3p: 'Optional[AssistInfo]' = None, foul: 'Optional[ShotClockStats]' = None, player_shot_info: 'Optional[PlayerShotInfo]' = None, pts: 'int' = 0, plus_minus: 'int' = 0) -> None

A lineup event's full counting-stat tree (LineupEventStats,

LineupEventStats.scala:7-38).

Only num_events/num_possessions/pts/plus_minus are exercised by Phase 5a -- see the module docstring's scope note.

Parameters

ParameterTypeDefaultDescription
num_eventsint0Number of raw events folded into this lineup event.
num_possessionsint0Number of possessions attributed to this lineup event.
fgFieldGoalStats<factory>Overall field-goal stats.
fg_rimFieldGoalStats<factory>Rim field-goal stats.
fg_midFieldGoalStats<factory>Mid-range field-goal stats.
fg_2pFieldGoalStats<factory>2pt field-goal stats.
fg_3pFieldGoalStats<factory>3pt field-goal stats.
ftFieldGoalStats<factory>Free-throw stats.
orbOptional[ShotClockStats]NoneOffensive-rebound stats, if tracked.
drbOptional[ShotClockStats]NoneDefensive-rebound stats, if tracked.
toShotClockStats<factory>Turnover stats.
stlOptional[ShotClockStats]NoneSteal stats, if tracked.
blkOptional[ShotClockStats]NoneBlock stats, if tracked.
assistOptional[ShotClockStats]NoneAssist stats, if tracked.
ast_rimOptional[AssistInfo]NoneRim-shot assist info, if tracked.
ast_midOptional[AssistInfo]NoneMid-range-shot assist info, if tracked.
ast_3pOptional[AssistInfo]None3pt-shot assist info, if tracked.
foulOptional[ShotClockStats]NoneFoul stats, if tracked.
player_shot_infoOptional[PlayerShotInfo]NonePer-player shot-quality info, if tracked.
ptsint0Points scored.
plus_minusint0Point differential while this lineup was on the floor.

Methods

LineupEventStats.empty​

LineupEventStats.empty() -> "'LineupEventStats'"

A fresh all-defaults LineupEventStats (:41).

LineupId​

LineupId(value: 'str') -> None

The set of players on the floor, as an opaque id string

(LineupEvent.LineupId, LineupEvent.scala:172, AnyVal).

Parameters

ParameterTypeDefaultDescription
valuestrThe opaque lineup identifier.

LocationType​

LocationType(*values)

Game location (Game.LocationType, Game.scala:36-38).

PlayerCodeId​

PlayerCodeId(code: 'str', id: 'PlayerId', ncaa_id: 'Optional[str]' = None) -> None

A player's within-team-season code paired with their full identity

(LineupEvent.PlayerCodeId, LineupEvent.scala:185-189).

Parameters

ParameterTypeDefaultDescription
codestrThe player code, unique within the team/season only.
idPlayerIdThe player's globally-unique identity.
ncaa_idOptional[str]NoneThe player's NCAA-issued id, if known.

PlayerEvent​

PlayerEvent(player: 'PlayerCodeId', player_stats: 'LineupEventStats', date: 'datetime', location_type: 'LocationType', start_min: 'float', end_min: 'float', duration_mins: 'float', score_info: 'ScoreInfo', team: 'TeamSeasonId', opponent: 'TeamSeasonId', lineup_id: 'LineupId', players: 'list[PlayerCodeId]', players_in: 'list[PlayerCodeId]', players_out: 'list[PlayerCodeId]', raw_game_events: 'list[RawGameEvent]', team_stats: 'LineupEventStats', opponent_stats: 'LineupEventStats', player_count_error: 'Optional[int]' = None) -> None

A lineup event's stats, narrowed to one player (PlayerEvent,

models/ncaa/PlayerEvent.scala:48-70). Scope addition, Task 5c.4 -- deferred by 5a since only ~sportsdataverse.mbb .mbb_ncaa_lineup_enrich.create_player_events (5c.4) returns it. Appended here (not inserted among the 5a-reviewed classes above) to keep this an additive-only change.

Same field shape as LineupEvent with two fields prepended (player, player_stats) -- the Scala builds this via a shapeless.LabelledGeneric HList splice of PlayerEvent's own player/player_stats onto every field of a LineupEvent instance; this port has no generic-programming machinery, so ~sportsdataverse.mbb.mbb_ncaa_lineup_enrich.create_player_events constructs the dataclass directly instead.

SingleEventMeta / event_meta / game_id are NOT ported. PlayerEvent.scala's companion object nests a SingleEventMeta case class, but the two fields that would carry it (event_meta, game_id) are commented out in the Scala source itself (PlayerEvent.scala:67-69) -- never part of the live case class, and create_player_events never constructs a SingleEventMeta. Nothing to defer; there is no live field to port.

Parameters

ParameterTypeDefaultDescription
playerPlayerCodeIdThe player this narrowed event describes.
player_statsLineupEventStatsThe player's own numerical stats for this lineup event.
datedatetimeThe date of the game.
location_typeLocationTypeHome/away/neutral (etc.) for this game.
start_minfloatThe point in the game at which the lineup entered.
end_minfloatThe point in the game at which the lineup changed.
duration_minsfloatThe duration of the lineup.
score_infoScoreInfoThe score differential context for this event.
teamTeamSeasonIdThe team under analysis.
opponentTeamSeasonIdThe opposing team.
lineup_idLineupIdA string that defines the set of players on the floor.
playerslist[PlayerCodeId]Mapping from player code to full identity, for this lineup.
players_inlist[PlayerCodeId]Players who subbed in for this event.
players_outlist[PlayerCodeId]Players who subbed out for this event.
raw_game_eventslist[RawGameEvent]The raw NCAA event strings for both teams.
team_statsLineupEventStatsNumerical stats extracted for the lineup (team side).
opponent_statsLineupEventStatsNumerical stats extracted for the lineup (opponent side).
player_count_errorOptional[int]NoneIf the lineup is "impossible", the number of players actually seen (for analysis purposes).

PlayerShotInfo​

PlayerShotInfo(unknown_3pm: 'Optional[tuple[int, int, int, int, int]]' = None, early_3pa: 'Optional[tuple[int, int, int, int, int]]' = None, unast_3pm: 'Optional[tuple[int, int, int, int, int]]' = None, ast_3pm: 'Optional[tuple[int, int, int, int, int]]' = None) -> None

Per-player shot-quality info, keyed by lineup slot

(LineupEventStats.PlayerShotInfo, LineupEventStats.scala:98-103). Each tuple is a fixed-arity 5-slot (one per lineup spot), mirroring the Scala PlayerTuple[Int] = Tuple5[Int, Int, Int, Int, Int] alias.

Parameters

ParameterTypeDefaultDescription
unknown_3pmOptional[tuple[int, int, int, int, int]]None3pt makes of unknown assist status, per slot.
early_3paOptional[tuple[int, int, int, int, int]]NoneEarly-shot-clock 3pt attempts, per slot.
unast_3pmOptional[tuple[int, int, int, int, int]]NoneUnassisted 3pt makes, per slot.
ast_3pmOptional[tuple[int, int, int, int, int]]NoneAssisted 3pt makes, per slot.

PlayerValueConstants​

PlayerValueConstants(pace_baseline: 'float', bubble_recruit_rank: 'int', bundle_prefix: 'str') -> None

Per-league constants for the player-value spine.

Parameters

ParameterTypeDefaultDescription
pace_baselinefloatLeague baseline possessions per game (per-100 scaling).
bubble_recruit_rankintNational recruit rank of a "bubble" high-major rotation player (recruiting-model reference point).
bundle_prefixstrArtifact filename prefix under mbb/models ("mbb" / "wbb").

PossCalcFragment​

PossCalcFragment(shots_made_or_missed: 'int' = 0, liveball_orbs: 'int' = 0, actual_deadball_orbs: 'int' = 0, ft_events: 'int' = 0, ignored_and_ones: 'int' = 0, bad_fouls: 'int' = 0, offsetting_bad_fouls: 'int' = 0, turnovers: 'int' = 0) -> None

Running stats needed to calculate possessions for one lineup event,

one direction at a time (PossessionUtils.PossCalcFragment, PossessionUtils.scala:124-144).

Parameters

ParameterTypeDefaultDescription
shots_made_or_missedint0Count of shot attempts (made or missed).
liveball_orbsint0Count of live-ball offensive rebounds.
actual_deadball_orbsint0Count of dead-ball offensive rebounds.
ft_eventsint0Count of free-throw sets (capped-at-1 flag per set).
ignored_and_onesint0Count of and-one free throws ignored for possession purposes (capped-at-1 flag).
bad_foulsint0Count of technical/flagrant fouls counted against the defending side (capped-at-1 flag).
offsetting_bad_foulsint0Count of technical/flagrant fouls that offset (net zero) rather than counting against either side (capped-at-1 flag).
turnoversint0Count of turnovers.

PossessionEvent​

PossessionEvent(dir: 'Direction') -> None

Decomposes RawGameEvent\ s into attacking/defending sides

(RawGameEvent.PossessionEvent, LineupEvent.scala:126-149).

Parameters

ParameterTypeDefaultDescription
dirDirectionWhich team (Direction.TEAM / Direction.OPPONENT) is currently in possession.

Methods

PossessionEvent.attacking_team​

PossessionEvent.attacking_team(ev: 'RawGameEvent') -> 'Optional[str]'

The event string for the team in possession, or None.

Parameters

ParameterTypeDefaultDescription
evRawGameEventThe raw game event to inspect.

Returns

ev.team if dir is Direction.TEAM, ev.opponent if Direction.OPPONENT, else None.

PossessionEvent.defending_team​

PossessionEvent.defending_team(ev: 'RawGameEvent') -> 'Optional[str]'

The event string for the team NOT in possession, or None.

Parameters

ParameterTypeDefaultDescription
evRawGameEventThe raw game event to inspect.

Returns

ev.team if dir is Direction.OPPONENT, ev.opponent if Direction.TEAM, else None.

RapmConfig​

RapmConfig(...)

Port of RapmConfig (RapmUtils.ts:175-179).

RapmPlayerContext​

RapmPlayerContext(...)

Port of RapmPlayerContext (RapmUtils.ts:147-173).

See the module docstring for why filtered_lineups is a Python callable rather than a materialized dict.

RapmPreProcDiagnostics​

RapmPreProcDiagnostics(...)

Port of RapmPreProcDiagnostics (RapmUtils.ts:187-194) -- the

multi-collinearity diagnostic calc_collinearity_diag returns.

RapmPriorInfo​

RapmPriorInfo(...)

Port of RapmPriorInfo (RapmUtils.ts:124-133).

RapmProcessingInputs​

RapmProcessingInputs(...)

Port of RapmProcessingInputs (RapmUtils.ts:196-203).

See the module docstring's "Task 3.5 notes" for why soln_matrix and sd_rapm are plain nested lists rather than NDArrays, and why sd_rapm exists at all (a Python-only addition beyond upstream's own return shape).

RawGameEvent​

RawGameEvent(min: 'float', team: 'Optional[str]' = None, opponent: 'Optional[str]' = None) -> None

A single NCAA play-by-play event line (LineupEvent.RawGameEvent,

LineupEvent.scala:65-105).

Exactly one of team / opponent is populated per event -- the raw string is the literal "date,time,event" line from the NCAA website.

Parameters

ParameterTypeDefaultDescription
minfloatThe game-clock minute (fractional) this event occurred at.
teamOptional[str]NoneThe raw event string, if this event belongs to the team under analysis.
opponentOptional[str]NoneThe raw event string, if this event belongs to the opponent.

Methods

RawGameEvent.for_opponent​

RawGameEvent.for_opponent(s: 'str', min: 'float') -> "'RawGameEvent'"

Build an opponent-side event (Scala ``RawGameEvent.opponent(s,

min), LineupEvent.scala:109-110-- renamed per the "Scala idiom decisions" module note to avoid colliding with theopponent`` field).

Parameters

ParameterTypeDefaultDescription
sstr
minfloat

RawGameEvent.for_team​

RawGameEvent.for_team(s: 'str', min: 'float') -> "'RawGameEvent'"

Build a team-side event (Scala RawGameEvent.team(s, min),

LineupEvent.scala:107-108 -- renamed per the "Scala idiom decisions" module note to avoid colliding with the team field).

Parameters

ParameterTypeDefaultDescription
sstr
minfloat

RosterEntry​

RosterEntry(player_code_id: 'PlayerCodeId', number: 'str', pos: 'str', height: 'str', height_in: 'Optional[int]', year_class: 'str', gp: 'int', origin: 'Optional[str]', role: 'Optional[str]') -> None

An entry in an NCAA team roster (RosterEntry, ``models/ncaa

/RosterEntry.scala:11-21). **Scope addition, Task 5e.1** -- the first model consumed by the HTML-parser layer (mbb_ncaa_roster_parser.py``). Appended here (not inserted among the 5a-reviewed classes above) to keep this an additive-only change, matching PlayerEvent's precedent.

The trailing role field (present in the Scala case class shape but never populated by RosterParser.parse_roster -- every construction site there, both the real-player and coach__branches, passes the literalNone for it) is presumably set by a later phase's box-score parser (BoxscoreParser`, out of this task's scope); it is carried here for shape fidelity even though Task 5e.1's only producer never populates it.

Parameters

ParameterTypeDefaultDescription
player_code_idPlayerCodeIdThe player's code + full identity (the roster-row equivalent of a box-score/PbP player reference).
numberstrThe jersey number, as printed (may be non-numeric text).
posstrThe listed position.
heightstrThe listed height, in "FT-IN" text form (e.g. "6-3").
height_inOptional[int]height parsed to total inches, if it matched height_regex.
year_classstrThe listed academic year ("Fr"/"So"/"Jr"/ "Sr"/etc.).
gpintGames played.
originOptional[str]The player's hometown/prior-school text, if the source table has that column (v1 rosters only).
roleOptional[str]Reserved for a later phase; always None from parse_roster (see above).

ScoreInfo​

ScoreInfo(start: 'Score', end: 'Score', start_diff: 'int', end_diff: 'int') -> None

Score context at the start/end of a lineup event

(LineupEvent.ScoreInfo, LineupEvent.scala:153-158).

Parameters

ParameterTypeDefaultDescription
startScoreScore at the start of the event.
endScoreScore at the end of the event.
start_diffintScore differential (team - opponent) at the start.
end_diffintScore differential (team - opponent) at the end.

Methods

ScoreInfo.empty​

ScoreInfo.empty() -> "'ScoreInfo'"

A fresh zeroed ScoreInfo (ScoreInfo.empty, :161-166).

ShotClockStats​

ShotClockStats(total: 'int' = 0, early: 'Optional[int]' = None, mid: 'Optional[int]' = None, late: 'Optional[int]' = None, orb: 'Optional[int]' = None) -> None

Counting stats broken down by shot-clock segment

(LineupEventStats.ShotClockStats, LineupEventStats.scala:51-57).

Parameters

ParameterTypeDefaultDescription
totalint0Count across the entire shot clock.
earlyOptional[int]NoneCount in the first 10s, if tracked.
midOptional[int]NoneCount in the middle 10s, if tracked.
lateOptional[int]NoneCount in the last 10s, if tracked.
orbOptional[int]NoneCount in the first 10s following an offensive rebound, if tracked (else folded into mid/late as normal).

ShotEvent​

ShotEvent(player: 'Optional[PlayerCodeId]', date: 'datetime', location_type: 'LocationType', team: 'TeamSeasonId', opponent: 'TeamSeasonId', is_off: 'bool', lineup_id: 'Optional[LineupId]', players: 'list[PlayerCodeId]', score: 'Score', min: 'float', loc: 'ShotLocation', geo: 'ShotGeo', dist: 'float', pts: 'int', value: 'int', ast_by: 'Optional[PlayerCodeId]', is_ast: 'Optional[bool]', is_trans: 'Optional[bool]', raw_event: 'Optional[str]') -> None

Info about one shot taken during a game, all distances in feet

(ShotEvent, models/ncaa/ShotEvent.scala:9-29). Scope addition, Task 5e.5 -- the model produced by ~sportsdataverse.mbb.mbb_ncaa_shot_parser.create_shot_event_data.

Fields mbb_ncaa_shot_parser.create_shot_event_data (this task) actually populates: player (best-effort -- tidy-resolved + coded for the team under analysis, name-coded only for the opponent), date/location_type/team/opponent (copied from the box-score lineup), is_off, score (re-oriented for home/away/ neutral perspective), min (ascending game-clock time, after phase1_shot_event_enrichment), loc/dist (transformed court coordinates + Euclidean distance from the basket, after the self-correcting flip pass), geo (synthetic lat/lon), raw_event (the SVG <title> text, for debugging).

Fields left as placeholders for a LATER phase (Task 5e.6, PlayByPlayUtils/ShotEnrichmentUtils): lineup_id (always None here -- "discard if bad lineup" per the Scala comment, filled in once the shot is matched against an actual on-floor lineup), players (always [] here -- filled in from the matched lineup), pts (not the real point value -- this task only sets it to 1/0 for made/missed, matching the Scala's own // (enrich in final phase) comment; the real 2pt/3pt value comes from PlayByPlayUtils.shot_value in Task 5e.6), value (always 0 here, same "final phase" note), ast_by/is_ast/is_trans (always None here -- assist/ transition attribution needs the play-by-play cross-reference Task 5e.6 builds).

Parameters

ParameterTypeDefaultDescription
playerOptional[PlayerCodeId]The shooting player's code + identity, if resolved (None is never actually produced by this task's parser, but the type allows for it per the Scala Option).
datedatetimeThe date of the game.
location_typeLocationTypeHome/away/neutral (etc.) for this game.
teamTeamSeasonIdThe team under analysis.
opponentTeamSeasonIdThe opposing team.
is_offboolWhether the team under analysis is the one shooting.
lineup_idOptional[LineupId]The on-floor lineup id, if/when matched (see above).
playerslist[PlayerCodeId]The on-floor lineup's players, if/when matched (see above).
scoreScoreThe score at the time of the shot, team-oriented.
minfloatThe ascending game-clock time (minutes) of the shot.
locShotLocationThe shot's transformed court location, in feet.
geoShotGeoThe shot's synthetic lat/lon.
distfloatThe shot's distance from the basket, in feet.
ptsintMade(1)/missed(0) flag from this task -- NOT the real point value (see above).
valueintAlways 0 from this task (see above).
ast_byOptional[PlayerCodeId]The assisting player, if/when matched (see above).
is_astOptional[bool]Whether the shot was assisted, if/when matched (see above).
is_transOptional[bool]Whether the shot was in transition, if/when matched (see above).
raw_eventOptional[str]The raw SVG <title> text this shot was parsed from, for debugging (discarded before writing to disk upstream).

ShotGeo​

ShotGeo(lat: 'float', lon: 'float') -> None

A shot's synthetic lat/lon, for geo-aware visualization tooling

(ShotEvent.ShotGeo, models/ncaa/ShotEvent.scala:45). Scope addition, Task 5e.5 -- flattened per ShotLocation's note.

Parameters

ParameterTypeDefaultDescription
latfloatSynthetic latitude (feet-to-meters converted, offset from an arbitrary base point -- not a real-world location).
lonfloatSynthetic longitude, same convention as lat.

ShotLocation​

ShotLocation(x: 'float', y: 'float') -> None

A shot's court-relative coordinates, in feet (ShotEvent.ShotLocation,

models/ncaa/ShotEvent.scala:48). Scope addition, Task 5e.5 -- flattened out of the Scala ShotEvent companion object per this module's established nested-object-flattening precedent (see the module docstring's "Scala idiom decisions": ScoreInfo/PlayerCodeId were already flattened out of LineupEvent's companion the same way).

Parameters

ParameterTypeDefaultDescription
xfloatFeet from the basket; positive is to the right of the basket (facing the goal), negative is to the left.
yfloatFeet from the basket along the baseline-perpendicular axis.

TeamId​

TeamId(name: 'str') -> None

CBB team identifier (TeamId, TeamId.scala, AnyVal).

Parameters

ParameterTypeDefaultDescription
namestrThe unique team name.

TeamSeasonId​

TeamSeasonId(team: 'TeamId', year: 'Year') -> None

A team's season identifier (TeamSeasonId, TeamSeasonId.scala).

Parameters

ParameterTypeDefaultDescription
teamTeamIdThe team playing the season.
yearYearThe year the season ends.

adjust_efficiency​

adjust_efficiency(game_eff: 'pl.DataFrame', *, league: 'str' = 'mens', max_iter: 'int' = 100, tol: 'float' = 0.0001) -> 'pl.DataFrame'

Iterative opponent-adjusted efficiency -> AdjO / AdjD / AdjEM per team-season.

KenPom-style fixed point: initialise adj_o = raw_o / adj_d = raw_d, then repeatedly recompute each team's rating from its games with the opponent's current adjusted rating and a home-court adjustment removed, until the largest change is below tol. Ratings are computed independently per season (a team's opponent pool is within-season).

The per-game offensive update is off_eff - (adj_d_opp - avg) - loc_o where loc_o is +hfa/2 at home, -hfa/2 away, 0 neutral (defense is symmetric with the opposite sign); avg is the league mean efficiency and hfa comes from ~sportsdataverse.mbb.mbb_prediction_constants.get_constants.

Parameters

ParameterTypeDefaultDescription
game_effDataFrameOutput of raw_game_efficiency.
leaguestr'mens'"mens" / "womens" -- selects the HFA constant.
max_iterint100Maximum fixed-point iterations.
tolfloat0.0001Convergence tolerance on the largest rating change.

Returns

One row per (season, team_id): season, team_id, adj_o, adj_d, adj_em, raw_o, raw_d, games. Empty input returns that schema with zero rows.

col_nametypedescription
seasonintegerSeason year.
team_idcharacterUnique team identifier.
adj_odoubleAdj o.
adj_ddoubleAdj d.
adj_emdoubleAdj em.
raw_odoubleRaw o.
raw_ddoubleRaw d.
gamesintegerGames played.

Example

from sportsdataverse.mbb.mbb_team_ratings import adjust_efficiency, raw_game_efficiency
ratings = adjust_efficiency(raw_game_efficiency(sched, box))

adjust_off_rating_stats​

adjust_off_rating_stats(pts_correction_factor: 'float', poss_correction_factor: 'float', mutable_o_rtg: 'ORtgDiagnostics', maybe_raw_o_rtg: 'float | None') -> 'tuple[float, float] | None'

Apply a missing-possession correction factor to an ORtgDiagnostics dict in place.

Faithful port of RatingUtils.adjustOffRatingStats (RatingUtils.ts:993-1033). Genuinely public upstream (called from LineupTableUtils.ts after a lineup-level pts/poss reconciliation), so this port is public too. Recomputes the productivity fields via build_productivity (reused, not re-derived).

Landmine 4 (see module docstring): the o_adj = avgEff / defSos or 1 recomputation here is unguarded against defSos == 0 -- same reachability analysis as landmine 3 (only reachable if the diagnostics dict's original build_o_rtg call used avg_efficiency == 0).

Parameters

ParameterTypeDefaultDescription
pts_correction_factorfloatPoints correction factor (e.g. team pts / sum of player pts, capped to [0.95, 1.05] by callers).
poss_correction_factorfloatPossession correction factor, same shape.
mutable_o_rtgORtgDiagnosticsThe ORtgDiagnostics dict to mutate in place (oRtg, Usage, adjORtg, adjORtgPlus, Usage_Bonus, SoS_Bonus, adjPtsFactor, adjPossFactor, and (conditionally) Raw_Usage are all updated).
maybe_raw_o_rtgfloat | NoneThe un-overridden raw oRtg value (rawORtg's .value, or None when no override was in play), used to compute the raw-side return.

Returns

(new_raw_o_rtg, raw_adj_o_rtg_plus) when both mutable_o_rtg["Raw_Usage"] and maybe_raw_o_rtg are not None; otherwise None (.isNilsemantics -- an explicit0` does NOT count as nil).

Example

from sportsdataverse.mbb.mbb_ratings import build_o_rtg, adjust_off_rating_stats

_, _, raw_o_rtg, _, o_diags = build_o_rtg(player, {}, {}, 100.0, True, False)
maybe_raw = raw_o_rtg["value"] if raw_o_rtg else None
adjust_off_rating_stats(1.1, 0.9, o_diags, maybe_raw)
print(o_diags["oRtg"], o_diags["adjORtgPlus"])

adjust_tempo​

adjust_tempo(game_eff: 'pl.DataFrame', *, league: 'str' = 'mens', max_iter: 'int' = 100, tol: 'float' = 0.0001) -> 'pl.DataFrame'

Opponent-adjusted tempo (possessions/40) per team-season.

Same fixed point as adjust_efficiency, applied to game possessions under the additive model poss = tempo_i + tempo_j - avg: a team's tempo is recovered by removing its opponents' current adjusted tempo. avg is the league baseline tempo from ~sportsdataverse.mbb.mbb_prediction_constants.get_constants.

Parameters

ParameterTypeDefaultDescription
game_effDataFrameOutput of raw_game_efficiency.
leaguestr'mens'"mens" / "womens" -- selects the tempo baseline.
max_iterint100Maximum fixed-point iterations.
tolfloat0.0001Convergence tolerance on the largest tempo change.

Returns

One row per (season, team_id): season, team_id, adj_tempo. Empty input returns that schema with zero rows.

col_nametypedescription
seasonintegerSeason year.
team_idcharacterUnique team identifier.
adj_tempodouble

Example

from sportsdataverse.mbb.mbb_team_ratings import adjust_tempo, raw_game_efficiency
tempo = adjust_tempo(raw_game_efficiency(sched, box))

aggregate_player_seasons​

aggregate_player_seasons(seasons: "'list[int]'", *, league: 'str' = 'mens') -> 'pl.DataFrame'

Canonical per-player-season counting frame from the boxscore release.

Sums the per-game player boxscores into one row per (player_id, season, team_id) with the counting columns player_per100_features expects. Shot-location splits come from the shots release (2025+): free throws (MadeFreeThrow) are excluded, layup/dunk/tip = rim, and jump shots split three vs mid by score_value (the release's type_text carries no three-point marker; score_value is populated on misses too). For seasons without shots data, three-point attempts come from the box and all remaining attempts fold into fga_mid.

Parameters

ParameterTypeDefaultDescription
seasonslist[int]Seasons to aggregate.
leaguestr'mens'"mens" or "womens".

Returns

One row per (player_id, season, team_id): player_id:Utf8, season, team_id:Utf8, player, minutes + the counting columns + fga_rim, fga_mid, fga_three. Empty input returns zero rows.

col_nametypedescription
seasonintegerSeason year.
team_idcharacterUnique team identifier.
playercharacterPlayer name.
positioncharacterListed roster position (G, F, C, etc.).
minutesdoubleMinutes played, formatted MM:SS (V3 PT-duration parsed) or decimal minutes (V2).
field_goals_madedoubleField goals made (2-pt + 3-pt).
field_goals_attempteddoubleField goal attempts (2-pt + 3-pt).
three_point_field_goals_madedoubleThree-point field goals made.
three_point_field_goals_attempteddoubleThree-point field goal attempts.
free_throws_madedoubleFree throws made.
free_throws_attempteddoubleFree throw attempts.
offensive_reboundsdoubleOffensive rebounds.
defensive_reboundsdoubleDefensive rebounds.
assistsdoubleTotal assists.
stealsdoubleTotal steals.
blocksdoubleTotal blocks.
turnoversdoubleTotal turnovers.
pointsdoublePoints scored.
player_idcharacterUnique player identifier.
fga_rimdouble
fga_middouble
fga_threedouble

Example

from sportsdataverse.mbb.mbb_player_value_constants import (
aggregate_player_seasons, player_per100_features,
)
feats = player_per100_features(aggregate_player_seasons([2025]))

apply_weak_priors​

apply_weak_priors(field: 'str', player_poss_pcts: 'list[float]', prior_info: 'RapmPriorInfo', debug_mode: 'bool' = False) -> 'Callable[[float, list[float]], list[float]]'

Build a closure that nudges ridge-regressed RAPM back towards its weak prior.

Faithful port of RapmUtils.applyWeakPriors (RapmUtils.ts:921-995). Ridge regression depresses estimates towards 0; this "fills" the team-total error (see pick_ridge_regression's [IMPORTANT-EQUATION-01] team-total reconciliation) back in using each player's weak (KenPom-derived) prior as the fallback signal, capped so no more than half the team-total error gets attributed via this path (max_multiplier = -0.5) -- an alternate flat-translation path (use_alt_rating) kicks in for off_adj_ppp/def_adj_ppp fields when the capped path can't fully explain the error.

Parameters

ParameterTypeDefaultDescription
fieldstrThe prior key to read off each prior_info["players_weak"] entry, e.g. "off_adj_ppp".
player_poss_pctslist[float]Per-player possession-share weights (index-aligned with prior_info["players_weak"]), e.g. pick_ridge_regression's own pct_by_player[off_or_def].
prior_infoRapmPriorInfoA RapmPriorInfo (only ["players_weak"] is read).
debug_modeboolFalseKept for TS signature parity -- upstream gates a console.log behind this flag (RapmUtils.ts:979-984), which this port deliberately does not reproduce: every production call site pins it False (offDefDebugMode.off/.def are hardcoded False constants inside pickRidgeRegression), so it is dead in every current caller and would only ever emit console noise, not test-observable behavior.

Returns

A closure (error, base_results) -> adjusted_results -- call it with the team-total efficiency error and the pre-adjustment RAPM vector to get the weak-prior-nudged result.

Example

from sportsdataverse.mbb.mbb_rapm import apply_weak_priors

nudge = apply_weak_priors("off_adj_ppp", pct_by_player, ctx["prior_info"])
adjusted = nudge(adj_eff_err_pre_prior, results_pre_prior)

as_of_ratings_split​

as_of_ratings_split(results: 'pl.DataFrame', cutoff_date: 'datetime.date') -> 'pl.DataFrame'

Filter a results frame to games strictly before a cutoff date (leakage boundary).

Parameters

ParameterTypeDefaultDescription
resultsDataFrameA polars.DataFrame with a date column.
cutoff_datedateGames on or after this date are excluded.

Returns

A polars.DataFrame containing only rows with date < cutoff_date.

col_nametypedescription
idintegerId.
uidcharacterESPN UID string.
attendancedoubleReported attendance.
time_validlogicalTime valid.
neutral_sitelogicalNeutral site.
conference_competitionlogicalConference competition.
play_by_play_availablelogical
recentlogicalRecent.
start_datecharacterStart date (YYYY-MM-DD).
notes_typecharacterNotes type.
notes_headlinecharacterNotes headline.
broadcast_marketcharacterBroadcast market label (e.g. 'national', 'home').
broadcast_namecharacterBroadcast name.
type_idintegerType identifier (numeric).
type_abbreviationcharacterType abbreviation.
venue_idintegerUnique venue identifier.
venue_full_namecharacterVenue full name.
venue_address_citycharacterVenue address city.
venue_address_statecharacterVenue address state / region.
venue_indoorlogicalTRUE if the venue is indoors.
status_clockdoubleStatus clock.
status_display_clockcharacterStatus display clock.
status_perioddoubleStatus period.
status_type_idintegerUnique identifier for status type.
status_type_namecharacterStatus type name.
status_type_statecharacterStatus type state.
status_type_completedlogicalStatus type completed.
status_type_descriptioncharacterStatus type description.
status_type_detailcharacterStatus type detail.
status_type_short_detailcharacterStatus type short detail.
format_regulation_periodsdoubleFormat regulation periods.
home_team_idintegerUnique identifier for the home team.
home_uidcharacterHome team's uid.
home_locationcharacterHome team's location.
home_namecharacterHome name.
home_abbreviationcharacterHome team's abbreviation.
home_display_namecharacterHome display name.
home_short_display_namecharacterHome short display name.
home_colorcharacterColor code (hex) for home.
home_alternate_colorcharacterColor code (hex) for home alternate.
home_is_activelogicalHome team's is active.
home_venue_idintegerUnique identifier for home venue.
home_logocharacterHome team logo URL.
home_conference_idintegerUnique identifier for home conference.
home_scoreintegerHome team score at the time of the play.
home_winnerlogicalHome team's winner.
home_current_rankdouble
home_linescorescharacter
home_recordscharacter
away_team_idintegerUnique identifier for the away team.
away_uidcharacterAway team's uid.
away_locationcharacterAway team's location.
away_namecharacterAway name.
away_abbreviationcharacterAway team's abbreviation.
away_display_namecharacterAway display name.
away_short_display_namecharacterAway short display name.
away_colorcharacterColor code (hex) for away.
away_alternate_colorcharacterColor code (hex) for away alternate.
away_is_activelogicalAway team's is active.
away_venue_idintegerUnique identifier for away venue.
away_logocharacterAway team logo URL.
away_conference_idintegerUnique identifier for away conference.
away_scoreintegerAway team score at the time of the play.
away_winnerlogicalAway team's winner.
away_current_rankdouble
away_linescorescharacter
away_recordscharacter
game_idintegerUnique game identifier.
seasonintegerSeason year.
season_typeintegerSeason type (1=pre-season, 2=regular season, 3=postseason, 4=off-season for ESPN; or string label for WNBA Stats).
status_type_alt_detailcharacterStatus type alt detail.
tournament_idintegerESPN tournament identifier.
groups_idintegerUnique identifier for groups.
groups_namecharacterGroups name.
groups_short_namecharacterGroups short name.
groups_is_conferencelogicalGroups is conference.
game_jsonlogical
game_json_urlcharacter
game_date_timecharacterGame start date/time (ISO 8601).
datecharacterDate in YYYY-MM-DD format.
PBPlogical
team_boxlogicalTeam box.
player_boxlogicalPlayer box.

Example

import datetime as dt
from sportsdataverse._common.metrics import as_of_ratings_split
as_of_ratings_split(results, dt.date(2023, 9, 8))

as_of_season_split​

as_of_season_split(df: 'pl.DataFrame', target_season: 'int') -> 'pl.DataFrame'

Rows strictly before target_season -- the leakage boundary.

Parameters

ParameterTypeDefaultDescription
dfDataFrameFrame with an integer season column.
target_seasonintThe season being predicted; its rows (and later) drop.

Returns

The subset with season < target_season.

col_nametypedescription
seasonintegerSeason year.
team_idcharacterUnique team identifier.
playercharacterPlayer name.
positioncharacterListed roster position (G, F, C, etc.).
minutesdoubleMinutes played, formatted MM:SS (V3 PT-duration parsed) or decimal minutes (V2).
field_goals_madedoubleField goals made (2-pt + 3-pt).
field_goals_attempteddoubleField goal attempts (2-pt + 3-pt).
three_point_field_goals_madedoubleThree-point field goals made.
three_point_field_goals_attempteddoubleThree-point field goal attempts.
free_throws_madedoubleFree throws made.
free_throws_attempteddoubleFree throw attempts.
offensive_reboundsdoubleOffensive rebounds.
defensive_reboundsdoubleDefensive rebounds.
assistsdoubleTotal assists.
stealsdoubleTotal steals.
blocksdoubleTotal blocks.
turnoversdoubleTotal turnovers.
pointsdoublePoints scored.
player_idcharacterUnique player identifier.
fga_rimdouble
fga_middouble
fga_threedouble

Example

from sportsdataverse.mbb.mbb_player_value_constants import as_of_season_split
prior = as_of_season_split(df, 2026)

bootstrap_ari​

bootstrap_ari(fit_fn: "'Callable[[np.ndarray], tuple[np.ndarray, np.ndarray]]'", X: 'np.ndarray', n_boot: 'int' = 20, seed: 'int' = 0) -> 'float'

Cluster stability: mean ARI between the full fit and bootstrap refits.

Parameters

ParameterTypeDefaultDescription
fit_fnCallable[[ndarray], tuple[ndarray, ndarray]]X -> (centers, labels) (e.g. a seeded kmeans_fit partial).
XndarrayFeature matrix.
n_bootint20Bootstrap resamples.
seedint0RNG seed.

Returns

Mean adjusted Rand index of the resample fits' assignments (of the FULL sample, via nearest refit center) vs the full-fit labels.

Example

from functools import partial
score = bootstrap_ari(lambda Z: kmeans_fit(Z, 8, seed=0), Z, n_boot=20, seed=0)

brier_score​

brier_score(y_true: 'np.ndarray', p_pred: 'np.ndarray') -> 'float'

Mean squared error between predicted probabilities and binary outcomes.

Parameters

ParameterTypeDefaultDescription
y_truendarrayArray of binary outcomes (0/1).
p_predndarrayArray of predicted probabilities in [0, 1].

Returns

The Brier score (0.0 is a perfect forecast).

Example

import numpy as np
from sportsdataverse._common.metrics import brier_score
brier_score(np.array([1, 0]), np.array([0.9, 0.1]))

build_d_rtg​

build_d_rtg(stat_set: 'LineupStatSet | None', avg_efficiency: 'float', calc_diags: 'bool', override_adjusted: 'bool') -> 'tuple[dict[str, float] | None, dict[str, float] | None, dict[str, float] | None, dict[str, float] | None, DRtgDiagnostics | None]'

Individual defensive rating (Dean-Oliver DRtg) + diagnostics.

Faithful port of RatingUtils.buildDRtg (RatingUtils.ts:1252-1485). Mirrors build_o_rtg's structure (stat_get closure, calc_diags/override_adjusted flag pair, recursive un-overridden raw-value pass) over the simpler (stat_set, avg_efficiency, calc_diags, override_adjusted) 4-arg signature (no roster/extra-team-stat args, confirmed against the TS).

Parameters

ParameterTypeDefaultDescription
stat_setLineupStatSet | NoneThe player's stat dict. None returns an all-None 5-tuple (RatingUtils.ts:1264-1265's if (!statSet) -- null/undefined only). Unlike build_o_rtg, an empty dict computes cleanly -- every division in buildDRtg is guard-ternary'd (see the module docstring's "Contrast" note), so {} does not raise ZeroDivisionError.
avg_efficiencyfloatLeague/context average efficiency (100 in every vendored jest call).
calc_diagsboolWhen True, populate the 5th tuple slot (DRtgDiagnostics); otherwise it is None.
override_adjustedboolWhen True, apply build_def_overridesto the raw opponent-FGM/points fields before computing, and additionally recurse once (withcalc_diags=False, override_adjusted=False`) to compute the un-overridden "raw" values for the 3rd/4th tuple slots.

Returns

A 5-tuple (d_rtg, adj_d_rtg, raw_d_rtg, raw_adj_d_rtg, d_rtg_diags): - d_rtg: {"value": DRtg} when Opponent_Possessions_Box > 0, else None. - adj_d_rtg: {"value": Adj_DRtgPlus} under the same guard. - raw_d_rtg / raw_adj_d_rtg: the un-overridden values from the recursive call when override_adjusted=True; None otherwise (unlike build_o_rtg, there is no internal-usage special case here -- the TS destructures only the first 2 slots of the recursive 5-tuple). - d_rtg_diags: the full DRtgDiagnostics dict (None unless calc_diags=True).

Example

from sportsdataverse.mbb.mbb_ratings import build_d_rtg

d_rtg, adj_d_rtg, _, _, diags = build_d_rtg(player, 100.0, True, False)
print(d_rtg["value"], diags["dRtg"])

# Override-adjusted (manual 3P-defense-% override applied)

d_rtg2, adj_d_rtg2, raw_d_rtg2, raw_adj_d_rtg2, _ = build_d_rtg(
player, 100.0, False, True,
)

build_mbb_season_wp​

build_mbb_season_wp(season: 'int', *, league: 'str' = 'mens', return_as_pandas: 'bool' = False) -> "Union[pl.DataFrame, 'pd.DataFrame']"

A season's play-by-play with win-probability columns joined in.

Loads the season's play-by-play, schedule, and team boxscores, builds a leakage-free weekly as-of pregame anchor per game, scores every play through the bundled in-game win-probability artifact, and returns the full load_mbb_pbp frame with pregame_home_prob + home_win_prob appended -- the enrich-in-place shape that overwrites the season's play_by_play_<season>.parquet release asset.

Parameters

ParameterTypeDefaultDescription
seasonintSeason year (e.g. 2024); bounded by load_mbb_pbp release availability (>= 2002).
leaguestr'mens'"mens" or "womens" (selects the loaders + constants).
return_as_pandasboolFalseReturn a pandas DataFrame instead of polars.

Returns

The season's load_mbb_pbp frame (every column preserved) with the two WP_COLSappended (bothFloat64), sorted by game_idthengame_play_number`.

col_nametypedescription
game_play_numberintegerSequential play number within the game.
idintegerId.
sequence_numberintegerSequence number representing a shot-possession (V3 PBP).
type_idintegerType identifier (numeric).
type_textcharacterDisplay text for the type field.
textcharacterText description of the play / record.
away_scoreintegerAway team score at the time of the play.
home_scoreintegerHome team score at the time of the play.
period_numberintegerNumeric period (1-4 for quarters; 5+ for OT).
period_display_valuecharacterPeriod display label (e.g. '1st Quarter', 'OT').
clock_display_valuecharacterGame clock display string (e.g. '8:32').
scoring_playlogicalTRUE if the play resulted in points scored.
score_valueintegerPoint value of the play (2 / 3 / 1).
team_idintegerUnique team identifier.
athlete_id_1integerPrimary athlete identifier (e.g. shooter).
wallclockcharacterWallclock.
shooting_playlogicalTRUE if the play was a shooting attempt.
athlete_id_2integerSecondary athlete identifier (e.g. assister / fouler).
game_idintegerUnique game identifier.
seasonintegerSeason year.
season_typeintegerSeason type (1=pre-season, 2=regular season, 3=postseason, 4=off-season for ESPN; or string label for WNBA Stats).
home_team_idintegerUnique identifier for the home team.
home_team_namecharacterHome team name.
home_team_mascotcharacterHome team mascot.
home_team_abbrevcharacterHome team three-letter abbreviation.
home_team_name_altcharacterAlternate home team name.
away_team_idintegerUnique identifier for the away team.
away_team_namecharacterAway team name.
away_team_mascotcharacterAway team mascot.
away_team_abbrevcharacterAway team three-letter abbreviation.
away_team_name_altcharacterAlternate away team name.
game_spreaddoubleGame spread (signed; positive = home favored).
home_favoritelogicalTRUE if the home team is the betting favorite.
game_spread_availablelogicalTRUE if a point spread was available.
home_team_spreaddoubleHome team's point spread.
halfintegerHalf of the game (1 or 2).
timecharacterTime / clock value.
clock_minutesintegerClock minutes split out for convenience.
clock_secondsintegerClock seconds split out for convenience.
home_timeout_calledlogical
away_timeout_calledlogical
lag_periodinteger
lead_periodinteger
lag_halfintegerA lag column on the half
lead_halfintegerA lead column on the half
start_period_seconds_remaininginteger
start_game_seconds_remainingintegerSeconds remaining in the game at the start of the play.
end_period_seconds_remaininginteger
end_game_seconds_remainingintegerSeconds remaining in the game at the end of the play.
game_datecharacterGame date (YYYY-MM-DD).
game_date_timecharacterGame start date/time (ISO 8601).
coordinate_xdoubleX coordinate on the court (half-court layout).
coordinate_ydoubleY coordinate on the court (half-court layout).
coordinate_x_rawdoubleX coordinate as returned by the API before any adjustment.
coordinate_y_rawdoubleY coordinate as returned by the API before any adjustment.
athlete_name_1character
athlete_name_2character
athlete_name_3character
media_idcharacterMedia identifier (video / image).
pregame_home_probdouble
home_win_probdouble

Example

from sportsdataverse.mbb import build_mbb_season_wp
wp = build_mbb_season_wp(2024)
wp.select("game_id", "game_play_number", "home_win_prob").head()

build_net_points​

build_net_points(player_rapm_and_poss_pct: 'LineupStatSet', ortg: 'ORtgDiagnostics', drtg: 'DRtgDiagnostics', avg_eff: 'float', scale_type: "Literal['T%', 'P%', '/G']", num_games: 'float' = 1, missing_game_adjustment: 'float' = 1) -> 'NetPoints'

Decompose ORtg/DRtg + RAPM into a Net-Points-like breakdown.

Faithful port of RatingUtils.buildNetPoints (RatingUtils.ts:1036-1234). Genuinely public upstream (called from buildLeaderboards.ts, PlayerImpactBreakdownTable.tsx, and ImpactBreakdownUtils.ts), so this port is public too.

Parameters

ParameterTypeDefaultDescription
player_rapm_and_poss_pctLineupStatSetThe player's stat dict -- reads off_team_poss_pct/def_team_poss_pct (nullish-coalesced to 0.0, see nullish) and, when present, off_adj_rapm/def_adj_rapm(each a{"value": float}` "Statistic"-shaped field) for the RAPM "with-or-without-you" (WOWY) deltas.
ortgORtgDiagnosticsAn ORtgDiagnostics dict from build_o_rtg (calc_diags=True), typically with adjPtsFactor/ adjPossFactor overridden from their 1 default by a missing-possession correction.
drtgDRtgDiagnosticsA DRtgDiagnostics dict from build_d_rtg (calc_diags=True). If it carries an onBallDiags key (this port's build_d_rtg never sets one -- see the module docstring's deferred-work note), the on-ball-adjusted branch is used instead of the base dRtg/adjDRtgPlus.
avg_efffloatLeague/context average efficiency.
scale_typeLiteral['T%', 'P%', '/G']"T%" (scale by on-floor team-possession share, avgEff-adjusted possession count), "P%" (scale to 100 possessions), or "/G" (scale to per-game).
num_gamesfloat1Divisor for the "/G" scale type. Default 1.
missing_game_adjustmentfloat1Multiplier folded into the "T%" scale factor for imputed-missing-games correction. Default 1.

Returns

A NetPoints dict -- 20 keys, plus an optional defNetPtsIndiv 21st key present only when drtg["onBallDiags"] is set (TS-verbatim key names throughout).

Example

from sportsdataverse.mbb.mbb_ratings import build_o_rtg, build_d_rtg, build_net_points

_, _, _, _, o_diags = build_o_rtg(player, {}, {}, 100.0, True, False)
_, _, _, _, d_diags = build_d_rtg(player, 100.0, True, False)
net_pts = build_net_points(player, o_diags, d_diags, 100.0, "T%")
print(net_pts["offNetPts"], net_pts["defNetPts"])

build_o_rtg​

build_o_rtg(stat_set: 'LineupStatSet | None', roster_stats_by_code: 'dict[str, LineupStatSet] | None', extra_team_stat_info: 'LineupStatSet', avg_efficiency: 'float', calc_diags: 'bool', override_adjusted: 'bool') -> 'tuple[dict[str, float] | None, dict[str, float] | None, dict[str, float] | None, dict[str, float] | None, ORtgDiagnostics | None]'

Individual offensive rating (Dean-Oliver ORtg) + diagnostics.

Faithful port of RatingUtils.buildORtg (RatingUtils.ts:398-960). See the module docstring for the signature-vs-brief note (this mirrors the TS 6-positional-arg / 5-tuple contract verbatim, snake_cased) and the diagnostics-dict key-naming convention (TS-verbatim, not snake_cased).

Parameters

ParameterTypeDefaultDescription
stat_setLineupStatSet | NoneThe player's LineupStatSet (ES-aggregation-shaped per-player doc, "IndivStatSet" upstream). None returns an all-None 5-tuple (RatingUtils.ts:412-413's if (!statSet) -- null/undefined only). An empty dict does NOT short-circuit ({} is truthy in JS and falls through to compute upstream); in this port it falls into unguarded-division landmine 1 and raises ZeroDivisionError where the TS degrades to a NaN-laced degenerate result -- see the module docstring's landmine list.
roster_stats_by_codedict[str, LineupStatSet] | None{player_code: LineupStatSet} for every player on the roster -- used for the approximate team-ORB apportionment and the per-shot-location assisted-eFG fallback. None is treated as {} (every vendored jest call passes a literal {}).
extra_team_stat_infoLineupStatSet{"total_off_to": {...}, "sum_total_off_to": {...}} -- team-level TOV bookkeeping used to compute "unblamed" team turnovers apportioned by off_team_poss_pct.
avg_efficiencyfloatLeague/context average efficiency (100 in every vendored jest call).
calc_diagsboolWhen True, populate the 5th tuple slot (ORtgDiagnostics); otherwise it is None.
override_adjustedboolWhen True, apply build_off_overridesto the raw made/attempt/turnover fields before computing, and additionally recurse once (withcalc_diags=False, override_adjusted=False`) to compute the un-overridden "raw" values for the 3rd/4th tuple slots.

Returns

A 5-tuple (o_rtg, adj_o_rtg, raw_o_rtg, raw_adj_o_rtg, o_rtg_diags): - o_rtg: {"value": ORtg} when TotPoss > 0, else None. - adj_o_rtg: {"value": Adj_ORtgPlus} when TotPoss > 0, else None. - raw_o_rtg: when calc_diags or override_adjusted, the un-overridden ORtg (None if override_adjusted=False, since no un-overridden pass was computed); otherwise a special internal-recursion value {"value": usage} (RatingUtils.ts:835's "if called internally return usage here" case). - raw_adj_o_rtg: the un-overridden adj_o_rtg (None when override_adjusted=False). - o_rtg_diags: the full ORtgDiagnostics dict (None unless calc_diags=True).

Example

from sportsdataverse.mbb.mbb_ratings import build_o_rtg

o_rtg, adj_o_rtg, _, _, diags = build_o_rtg(
player, {}, {"total_off_to": {"value": 0}, "sum_total_off_to": {}},
100.0, True, False,
)
print(o_rtg["value"], diags["oRtg"])

# Override-adjusted (manual shooting-% overrides applied)

o_rtg2, adj_o_rtg2, raw_o_rtg2, raw_adj_o_rtg2, _ = build_o_rtg(
player, {}, {"total_off_to": {"value": 0}, "sum_total_off_to": {}},
100.0, False, True,
)

build_player_context​

build_player_context(players: 'list[PlayerOnOffStats]', lineups: 'list[LineupStatSet]', players_baseline: 'dict[PlayerId, IndivStatSet]', stats_averages: 'PureStatSet', avg_efficiency: 'float', agg_value_key: 'ValueKey' = 'value', config: 'RapmConfig' = {'prior_mode': -1, 'removal_pct': 0.06, 'fixed_regression': -1}) -> 'RapmPlayerContext'

Build the context object the RAPM matrix-solve layer consumes.

Faithful port of RapmUtils.buildPlayerContext (RapmUtils.ts:427-541). Removes low-possession players (config["removal_pct"] of total on+off possessions), flags fully-removed lineups (mutating lineups in place -- see the module docstring's landmine 5), builds the player-to-column index, and folds build_priors into prior_info.

Parameters

ParameterTypeDefaultDescription
playerslist[PlayerOnOffStats]The per-player on/off splits (PlayerOnOffStats), e.g. mbb_lineup_stats.lineup_to_team_report(...)["players"].
lineupslist[LineupStatSet]The per-lineup LineupStatSet docs feeding this team's aggregate (mutated in place -- see landmine 5).
players_baselinedict[PlayerId, IndivStatSet]{player_id: IndivStatSet} -- forwarded to build_priors unchanged.
stats_averagesPureStatSetLeague/context average stat set -- forwarded to build_priors unchanged.
avg_efficiencyfloatLeague/context average efficiency.
agg_value_keyValueKey'value'"value" or "old_value" -- forwarded to build_priors as its value_key (only affects prior calculations, not the lineup-filtering/aggregation above it).
configRapmConfig{'prior_mode': -1, 'removal_pct': 0.06, 'fixed_regression': -1}Removal-percent / prior-mode / regression config. Defaults to DEFAULT_RAPM_CONFIG; never mutated by this function (only config["removal_pct"]/config["prior_mode"] are read), matching the TS default parameter's own read-only usage.

Returns

A RapmPlayerContext.

Example

from sportsdataverse.mbb.mbb_lineup_stats import lineup_to_team_report
from sportsdataverse.mbb.mbb_rapm import build_player_context, DEFAULT_RAPM_CONFIG

report = lineup_to_team_report({"lineups": buckets, "error_code": None})
ctx = build_player_context(
report["players"], buckets, {}, {}, 100.0, "value", DEFAULT_RAPM_CONFIG
)
print(ctx["num_players"], ctx["team_info"]["off_poss"]["value"])

# Filtering lineups by side (the ``filtered_lineups`` closure)

off_lineups = ctx["filtered_lineups"]("off")
def_lineups = ctx["filtered_lineups"]("def")

build_priors​

build_priors(players_baseline: 'dict[PlayerId, IndivStatSet]', stats_averages: 'PureStatSet', avg_efficiency: 'float', col_to_player: 'list[str]', prior_mode: 'float', value_key: 'ValueKey' = 'value') -> 'RapmPriorInfo'

Build strong/weak per-player RAPM priors for every column.

Faithful port of RapmUtils.buildPriors (RapmUtils.ts:237-407). See the module docstring's landmine list, item 1, for the critical Python-vs-JS {}-truthiness gotcha this function's implementation deliberately avoids.

Parameters

ParameterTypeDefaultDescription
players_baselinedict[PlayerId, IndivStatSet]{player_id: IndivStatSet} -- the most-general per-player baseline info (in production, sourced from mbb_ratings.build_productivity's output; see the module docstring's "RAPM prior source" note).
stats_averagesPureStatSetLeague/context average stat set, used by the (currently dead-code, see landmine 4) get_prior_basis fallback and by with_avg_or_undef's nil-check gate.
avg_efficiencyfloatLeague/context average efficiency.
col_to_playerlist[str]The player ids, in column order -- playersStrong/ playersWeak are index-aligned with this list.
prior_modefloat-1 for adaptive mode, -2 (or lower) for no prior, 0-1 for a fixed strong-prior weight.
value_keyValueKey'value'"value" or "old_value" -- allows priors to be built from luck-adjusted parameters.

Returns

A RapmPriorInfo.

Example

from sportsdataverse.mbb.mbb_rapm import build_priors

priors = build_priors({}, {}, 100.0, ["Wiggins, Aaron"], -1)
print(priors["players_weak"][0])