58 lines
1.6 KiB
Python
58 lines
1.6 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
|
|
from app.ml.training import FeatureModel
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class FeatureExplanation:
|
|
feature: str
|
|
current_value: float
|
|
predicted_value: float
|
|
change: float
|
|
direction: str
|
|
sample_count: int
|
|
historical_mean: float
|
|
historical_range: tuple[float, float]
|
|
standard_deviation: float
|
|
trend_per_step: float
|
|
confidence: float
|
|
summary: str
|
|
|
|
|
|
def explain_feature(
|
|
feature_name: str,
|
|
current_value: float,
|
|
predicted_value: float,
|
|
model: FeatureModel,
|
|
) -> FeatureExplanation:
|
|
change = predicted_value - current_value
|
|
direction = _direction(change)
|
|
summary = (
|
|
f"{feature_name}: {direction}; Prognose {predicted_value:.3f} "
|
|
f"aus aktuellem Wert {current_value:.3f} und Trend {model.slope:+.3f}. "
|
|
f"Basis: {model.sample_count} Messwerte, Mittelwert {model.mean:.3f}, "
|
|
f"Confidence {model.confidence:.0%}."
|
|
)
|
|
return FeatureExplanation(
|
|
feature=feature_name,
|
|
current_value=current_value,
|
|
predicted_value=predicted_value,
|
|
change=change,
|
|
direction=direction,
|
|
sample_count=model.sample_count,
|
|
historical_mean=model.mean,
|
|
historical_range=(model.minimum, model.maximum),
|
|
standard_deviation=model.standard_deviation,
|
|
trend_per_step=model.slope,
|
|
confidence=model.confidence,
|
|
summary=summary,
|
|
)
|
|
|
|
|
|
def _direction(change: float) -> str:
|
|
if abs(change) < 1e-12:
|
|
return "stabil"
|
|
return "steigend" if change > 0 else "fallend"
|