metrics: replace round-based percentile with linear interpolation (B5)
The previous implementation used round((n-1) * pct), which under Python's banker's rounding returned the upper-middle element on every even-length array (e.g. p50 of [1,2,3,4] returned 3 instead of 2.5). All summary JSONs were biased upward at p50 as a result. Match numpy.percentile's default linear interpolation between the two adjacent sorted values.
This commit is contained in:
@@ -101,7 +101,11 @@ def _stats(values: list[float | None]) -> dict[str, float] | None:
|
||||
|
||||
|
||||
def _percentile(sorted_vals: list[float], pct: float) -> float:
|
||||
if len(sorted_vals) == 1:
|
||||
n = len(sorted_vals)
|
||||
if n == 1:
|
||||
return sorted_vals[0]
|
||||
idx = round((len(sorted_vals) - 1) * pct)
|
||||
return sorted_vals[idx]
|
||||
rank = pct * (n - 1)
|
||||
lo = int(rank)
|
||||
hi = min(lo + 1, n - 1)
|
||||
frac = rank - lo
|
||||
return sorted_vals[lo] * (1 - frac) + sorted_vals[hi] * frac
|
||||
|
||||
Reference in New Issue
Block a user