ncaa_eval.model.elo module

Elo rating model — reference stateful model for NCAA tournament prediction.

Thin wrapper around EloFeatureEngine. All Elo math is delegated to the engine; this module adds StatefulModel ABC conformance, Pydantic configuration, JSON persistence, and plugin registration.

class ncaa_eval.model.elo.EloModel(config: EloModelConfig | None = None)[source]

Bases: StatefulModel

Elo rating model wrapping EloFeatureEngine.

get_config() EloModelConfig[source]

Return the Pydantic-validated configuration.

get_feature_importances() list[tuple[str, float]] | None[source]

Return top team Elo ratings as interpretability information.

get_state() dict[str, Any][source]

Return ratings and game counts as a serialisable snapshot.

classmethod load(path: Path) Self[source]

Reconstruct an EloModel from a saved directory.

Raises:

FileNotFoundError – If either config.json or state.json is missing. A missing file indicates an incomplete save() (e.g., interrupted write).

save(path: Path) None[source]

JSON-dump config, state, and feature config to path directory.

Creates the output directory, JSON-dumps the Pydantic config, then JSON-dumps the state dict (ratings and game counts) after coercing numeric keys to strings for JSON compatibility. Also writes the feature_config.json sidecar.

set_state(state: dict[str, Any]) None[source]

Restore ratings and game counts from a snapshot.

Parameters:

state – Must contain "ratings" (dict[int, float]) and "game_counts" (dict[int, int]) keys, as returned by get_state(). Keys may be int or str; string keys are coerced to int so that JSON-decoded dicts (where all keys are strings) work correctly without silent rating loss.

Raises:
  • KeyError – If "ratings" or "game_counts" keys are absent.

  • TypeError – If either value is not a dict.

start_season(season: int) None[source]

Delegate season transition to the engine.

update(game: Game) None[source]

Delegate game processing to the engine.

class ncaa_eval.model.elo.EloModelConfig(*, model_name: Literal['elo'] = 'elo', calibration_method: Literal['isotonic', 'sigmoid'] | None = None, initial_rating: float = 1500.0, k_early: float = 56.0, k_regular: float = 38.0, k_tournament: float = 47.5, early_game_threshold: int = 20, margin_exponent: float = 0.85, max_margin: int = 25, home_advantage_elo: float = 3.5, mean_reversion_fraction: float = 0.25)[source]

Bases: ModelConfig

Pydantic configuration for the Elo model.

Fields and defaults mirror EloConfig.

early_game_threshold: int
home_advantage_elo: float
initial_rating: float
k_early: float
k_regular: float
k_tournament: float
margin_exponent: float
max_margin: int
mean_reversion_fraction: float
model_config = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_name: Literal['elo']