All checks were successful
ENGIN CI / Build, test and smoke (push) Successful in 31s
87 lines
2.7 KiB
Python
87 lines
2.7 KiB
Python
"""Prediction model adapters used through a small dependency-injection boundary."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from typing import Protocol
|
|
|
|
import pandas as pd
|
|
|
|
from final_pipeline import (
|
|
DiagnosticModels,
|
|
predict_test,
|
|
train_models,
|
|
validate_submission,
|
|
)
|
|
|
|
from .errors import InferenceError
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class PredictionBundle:
|
|
submission: pd.DataFrame
|
|
diagnostics: pd.DataFrame
|
|
|
|
|
|
class PredictionModel(Protocol):
|
|
def predict(self, frame: pd.DataFrame) -> PredictionBundle: ...
|
|
|
|
|
|
class SklearnPredictionModel:
|
|
"""Thin adapter around the frozen, validated competition pipeline."""
|
|
|
|
def __init__(self, models: DiagnosticModels) -> None:
|
|
self._models = models
|
|
|
|
@classmethod
|
|
def train(
|
|
cls,
|
|
reference_frame: pd.DataFrame,
|
|
*,
|
|
random_state: int = 42,
|
|
n_jobs: int = -1,
|
|
) -> "SklearnPredictionModel":
|
|
try:
|
|
models = train_models(
|
|
reference_frame,
|
|
random_state=random_state,
|
|
n_jobs=n_jobs,
|
|
)
|
|
except Exception as exc:
|
|
raise InferenceError(
|
|
"Nie udało się przygotować modelu referencyjnego.",
|
|
hint="Sprawdź kompletność val.csv oraz zgodność wersji zależności.",
|
|
) from exc
|
|
return cls(models)
|
|
|
|
def predict(self, frame: pd.DataFrame) -> PredictionBundle:
|
|
try:
|
|
submission, diagnostics = predict_test(self._models, frame)
|
|
validate_submission(submission, frame)
|
|
except Exception as exc:
|
|
raise InferenceError(
|
|
"Model odrzucił pomiary podczas predykcji.",
|
|
hint="Zweryfikuj kompletność silników oraz brak nietypowych wartości w widmie.",
|
|
) from exc
|
|
return PredictionBundle(submission, diagnostics)
|
|
|
|
|
|
class PrecomputedPredictionModel:
|
|
"""Read-only demo fallback; accepts only the exact precomputed key set."""
|
|
|
|
def __init__(self, submission: pd.DataFrame, diagnostics: pd.DataFrame) -> None:
|
|
self._submission = submission.reset_index(drop=True).copy()
|
|
self._diagnostics = diagnostics.reset_index(drop=True).copy()
|
|
|
|
def predict(self, frame: pd.DataFrame) -> PredictionBundle:
|
|
keys = ["engine_id", "cylinder"]
|
|
if not frame[keys].reset_index(drop=True).equals(self._submission[keys]):
|
|
raise InferenceError(
|
|
"Tryb awaryjny obsługuje wyłącznie dołączony zestaw demonstracyjny.",
|
|
hint="Przywróć val.csv i uruchom ponownie aplikację, aby diagnozować własne pliki.",
|
|
)
|
|
return PredictionBundle(
|
|
self._submission.copy(),
|
|
self._diagnostics.copy(),
|
|
)
|