"""F 分布 CDF / p 值(纯标准库,无需 scipy)。 用正则不完全 beta 连分数(Numerical Recipes betacf/Lentz 法)计算 P(F ≤ f),供 ANOVA / 配合力显著性检验共用。 """ from __future__ import annotations import math def _betacf(a: float, b: float, x: float, itmax: int = 200, eps: float = 3e-14) -> float: qab, qap, qam = a + b, a + 1.0, a - 1.0 c = 1.0 d = 1.0 - qab * x / qap if abs(d) < 1e-30: d = 1e-30 d = 1.0 / d h = d for m in range(1, itmax + 1): m2 = 2 * m aa = m * (b - m) * x / ((qam + m2) * (a + m2)) d = 1.0 + aa * d if abs(d) < 1e-30: d = 1e-30 c = 1.0 + aa / c if abs(c) < 1e-30: c = 1e-30 d = 1.0 / d h *= d * c aa = -(a + m) * (qab + m) * x / ((a + m2) * (qap + m2)) d = 1.0 + aa * d if abs(d) < 1e-30: d = 1e-30 c = 1.0 + aa / c if abs(c) < 1e-30: c = 1e-30 d = 1.0 / d delta = d * c h *= delta if abs(delta - 1.0) < eps: break return h def _reg_beta(a: float, b: float, x: float) -> float: """正则不完全 beta I_x(a,b)。""" if x <= 0.0: return 0.0 if x >= 1.0: return 1.0 ln_beta = math.lgamma(a) + math.lgamma(b) - math.lgamma(a + b) bt = math.exp(a * math.log(x) + b * math.log1p(-x) - ln_beta) if x < (a + 1.0) / (a + b + 2.0): return bt * _betacf(a, b, x) / a return 1.0 - bt * _betacf(b, a, 1.0 - x) / b def f_cdf(f: float, d1: float, d2: float) -> float: """F 分布累积分布函数 P(F ≤ f),d1/d2 为两个自由度。""" if f <= 0.0 or d1 <= 0.0 or d2 <= 0.0: return 0.0 x = d1 * f / (d1 * f + d2) return _reg_beta(d1 / 2.0, d2 / 2.0, x) def f_pvalue(f: float, d1: float, d2: float) -> float: """双侧(右尾) p 值 = 1 - P(F ≤ f)。""" return 1.0 - f_cdf(f, d1, d2) def f_icdf(p: float, d1: float, d2: float, *, tol: float = 1e-9, max_iter: int = 200) -> float: """F 分布分位数(CDF 反解):求 f 使 P(F ≤ f) = p。 用二分法(f_cdf 关于 f 严格递增),适用于 DUS LSD 等需临界值场景; 高自由度下 F 值可能很大,上界从 1 起按 2 倍扩展。 """ p = max(min(p, 1.0 - 1e-12), 1e-12) lo, hi = 0.0, 1.0 while f_cdf(hi, d1, d2) < p and hi < 1e12: hi *= 2.0 for _ in range(max_iter): mid = 0.5 * (lo + hi) if f_cdf(mid, d1, d2) < p: lo = mid else: hi = mid if hi - lo < tol: break return 0.5 * (lo + hi) def t_crit(alpha: float, df: float) -> float: """双侧 t 分布临界值:P(|t| > t_crit) = alpha。 利用 t² ~ F(1, df)(df 为误差自由度),t_crit = √F_icdf(1-alpha, 1, df)。 """ return math.sqrt(f_icdf(1.0 - alpha, 1.0, df))