40 lines
1.1 KiB
Python
40 lines
1.1 KiB
Python
from __future__ import annotations
|
|
|
|
import numpy as np
|
|
|
|
|
|
def moving_average(values: list[float], window: int = 5) -> list[float]:
|
|
if len(values) < window:
|
|
return values
|
|
arr = np.array(values, dtype=float)
|
|
return np.convolve(arr, np.ones(window) / window, mode="valid").tolist()
|
|
|
|
|
|
def detect_anomalies(
|
|
values: list[float], threshold: float = 2.0
|
|
) -> list[dict]:
|
|
"""Detect anomalies using Z-score method."""
|
|
arr = np.array(values, dtype=float)
|
|
mean = np.mean(arr)
|
|
std = np.std(arr)
|
|
|
|
if std == 0:
|
|
return []
|
|
|
|
z_scores = np.abs((arr - mean) / std)
|
|
anomalies = []
|
|
for i, (val, z) in enumerate(zip(values, z_scores)):
|
|
if z > threshold:
|
|
anomalies.append({"index": i, "value": val, "z_score": float(z)})
|
|
return anomalies
|
|
|
|
|
|
def percentile_stats(values: list[float]) -> dict:
|
|
arr = np.array(values, dtype=float)
|
|
return {
|
|
"p50": float(np.percentile(arr, 50)),
|
|
"p90": float(np.percentile(arr, 90)),
|
|
"p95": float(np.percentile(arr, 95)),
|
|
"p99": float(np.percentile(arr, 99)),
|
|
}
|