Add artifact.metrics_analysis/src/artifact_metrics_analysis/core.py
This commit is contained in:
commit
15010cd591
1 changed files with 74 additions and 0 deletions
|
|
@ -0,0 +1,74 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Dict, Any
|
||||
import pandas as pd
|
||||
from statistics import mean
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
|
||||
class MetricResults:
|
||||
"""Repräsentation des Ergebnisses der Metrikanalyse inklusive Delta-Berechnung."""
|
||||
|
||||
def __init__(self, retry_tail_p99: float, band_width: float, delta_band_width: float) -> None:
|
||||
assert isinstance(retry_tail_p99, (int, float)), "retry_tail_p99 muss numerisch sein"
|
||||
assert isinstance(band_width, (int, float)), "band_width muss numerisch sein"
|
||||
assert isinstance(delta_band_width, (int, float)), "delta_band_width muss numerisch sein"
|
||||
|
||||
self.retry_tail_p99 = float(retry_tail_p99)
|
||||
self.band_width = float(band_width)
|
||||
self.delta_band_width = float(delta_band_width)
|
||||
|
||||
def to_dict(self) -> Dict[str, float]:
|
||||
"""Serialisiert die Ergebnisse als dictionary für JSON-Ausgabe."""
|
||||
return {
|
||||
"retry_tail_p99": self.retry_tail_p99,
|
||||
"band_width": self.band_width,
|
||||
"delta_band_width": self.delta_band_width,
|
||||
}
|
||||
|
||||
|
||||
class MetricDataError(Exception):
|
||||
"""Custom-Exception für ungültige Metrikdaten."""
|
||||
pass
|
||||
|
||||
|
||||
def analyze_metrics(card_data_40: Dict[str, Any], card_data_42: Dict[str, Any]) -> MetricResults:
|
||||
"""Vergleicht Metriken von zwei Evidence Cards anhand der Eingabedaten und erstellt eine Ergebnisanalyse."""
|
||||
if not isinstance(card_data_40, dict) or not isinstance(card_data_42, dict):
|
||||
raise MetricDataError("Beide Eingaben müssen Dictionaries sein.")
|
||||
|
||||
required_fields = {"retry_tail_p99", "band_width"}
|
||||
for cid, data in (("card_40", card_data_40), ("card_42", card_data_42)):
|
||||
missing = required_fields - data.keys()
|
||||
if missing:
|
||||
raise MetricDataError(f"Fehlende Felder in {cid}: {missing}")
|
||||
for field in required_fields:
|
||||
if not isinstance(data[field], (int, float)):
|
||||
raise MetricDataError(f"Ungültiger Typ für {field} in {cid}: {type(data[field])}")
|
||||
|
||||
df = pd.DataFrame([
|
||||
{"card": "40", **card_data_40},
|
||||
{"card": "42", **card_data_42}
|
||||
])
|
||||
|
||||
retry_tail_p99_avg = mean(df["retry_tail_p99"])
|
||||
bw_40 = df.loc[df["card"] == "40", "band_width"].iloc[0]
|
||||
bw_42 = df.loc[df["card"] == "42", "band_width"].iloc[0]
|
||||
delta_band_width = bw_42 - bw_40
|
||||
|
||||
logger.info("Analyse durchgeführt: ΔBandbreite=%.4f", delta_band_width)
|
||||
|
||||
result = MetricResults(
|
||||
retry_tail_p99=retry_tail_p99_avg,
|
||||
band_width=mean([bw_40, bw_42]),
|
||||
delta_band_width=delta_band_width,
|
||||
)
|
||||
|
||||
assert isinstance(result.retry_tail_p99, float)
|
||||
assert isinstance(result.band_width, float)
|
||||
assert isinstance(result.delta_band_width, float)
|
||||
|
||||
return result
|
||||
Loading…
Reference in a new issue