62 lines
1.6 KiB
Python
62 lines
1.6 KiB
Python
"""统计计算工具"""
|
||
import math
|
||
from typing import List
|
||
|
||
|
||
def _percentile_at(sorted_data: list[float], pct: float) -> float:
|
||
"""在线性插值下,返回排序后数据的指定百分位值。
|
||
|
||
注意:调用方必须确保 data 已排序。
|
||
"""
|
||
n = len(sorted_data)
|
||
if n == 0:
|
||
return 0.0
|
||
k = (pct / 100.0) * (n - 1)
|
||
f = math.floor(k)
|
||
c = math.ceil(k)
|
||
if f == c:
|
||
return sorted_data[int(k)]
|
||
d0 = sorted_data[int(f)] * (c - k)
|
||
d1 = sorted_data[int(c)] * (k - f)
|
||
return d0 + d1
|
||
|
||
|
||
def percentile(data: List[float], pct: float) -> float:
|
||
"""计算指定百分位数的值(线性插值)
|
||
|
||
空数据返回 0.0,调用方应通过检查 count 来判断是否有数据。
|
||
"""
|
||
return _percentile_at(sorted(data), pct)
|
||
|
||
|
||
def percentiles(data: List[float], pcts: List[float]) -> dict:
|
||
"""单次排序,批量计算多个百分位,返回 {pct: value}。"""
|
||
sorted_data = sorted(data)
|
||
return {p: _percentile_at(sorted_data, p) for p in pcts}
|
||
|
||
|
||
def mean(data: List[float]) -> float:
|
||
"""算术平均值"""
|
||
if not data:
|
||
return 0.0
|
||
return sum(data) / len(data)
|
||
|
||
|
||
def std(data: List[float]) -> float:
|
||
"""样本标准差(n-1)"""
|
||
if len(data) < 2:
|
||
return 0.0
|
||
m = mean(data)
|
||
variance = sum((x - m) ** 2 for x in data) / (len(data) - 1)
|
||
return math.sqrt(variance)
|
||
|
||
|
||
def min_val(data: List[float]) -> float:
|
||
"""最小值"""
|
||
return min(data) if data else 0.0
|
||
|
||
|
||
def max_val(data: List[float]) -> float:
|
||
"""最大值"""
|
||
return max(data) if data else 0.0
|