ChozhanMurugan
Initial deployment
0d7b049
Raw
History Blame Contribute Delete
1.55 kB
"""Inference wrapper around the saved LightGBM bundle."""
from __future__ import annotations
from dataclasses import dataclass
from functools import lru_cache
from pathlib import Path
import joblib
import numpy as np
import pandas as pd
from eca.config import settings
@dataclass
class Prediction:
prob_up: float
direction: int # 1 if up, 0 if down
confidence: float # |prob - 0.5| * 2
def as_dict(self) -> dict[str, float | int]:
return {"prob_up": self.prob_up, "direction": self.direction, "confidence": self.confidence}
class Predictor:
def __init__(self, bundle: dict):
self.model = bundle["model"]
self.feature_columns: list[str] = bundle["feature_columns"]
def predict_row(self, features: dict) -> Prediction:
row = {c: float(features.get(c, 0.0) or 0.0) for c in self.feature_columns}
X = pd.DataFrame([row], columns=self.feature_columns)
p = float(self.model.predict_proba(X)[:, 1][0])
return Prediction(prob_up=p, direction=int(p >= 0.5), confidence=float(abs(p - 0.5) * 2))
def predict_frame(self, df: pd.DataFrame) -> np.ndarray:
X = df.reindex(columns=self.feature_columns).astype(float).fillna(0.0)
return self.model.predict_proba(X)[:, 1]
@lru_cache(maxsize=1)
def load_model(path: Path | str | None = None) -> Predictor:
p = Path(path) if path else settings.model_path
if not p.exists():
raise FileNotFoundError(f"model not found at {p}; run `eca train` first")
return Predictor(joblib.load(p))